package com.opc.Controller;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.opc.Common.Code;
import com.opc.Common.MessageConstant;
import com.opc.Common.Result;
import com.opc.Config.CacheUtil;
import com.opc.Mapper.*;
import com.opc.Pojo.*;
import com.opc.PojoExt.AlarmStatistics;
import com.opc.PojoExt.ScrewExt;
import com.opc.Service.CarService;
import com.opc.Service.CarStatusService;
import com.opc.Service.JSerialCommIOService;
import com.opc.Service.ScrewService;
import com.opc.properties.CarTypeProperties;
import com.opc.properties.FrequencyProperties;
import com.opc.websocket.WebSocketServer;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.stream.Collectors;


@RestController
@Slf4j
@Transactional
@RequestMapping("/Screw")
public class ScrewController {

    @Autowired
    private ScrewService screwService;
    @Autowired
    private CarTypeProperties carTypeProperties;
    @Autowired
    private FrequencyProperties frequencyProperties;
    @Autowired
    private WebSocketServer webSocketServer;
    @Autowired
    private ScrewTypeMapper screwTypeMapper;
    @Autowired
    private CarService carService;
    @Autowired
    private TorqueStandardsMapper torqueStandardsMapper;
    @Autowired
    private ScrewMapper screwMapper;
    @Autowired
    private CarStatusService carStatusService;
    @Autowired
    private CarMapper carMapper;
    @Autowired
    private CarStatusMapper carStatusMapper;
    @Autowired
    private EmployeeMapper employeeMapper;
    @Autowired
    //@Qualifier("jSerialCommIOService")
    private JSerialCommIOService jSerialCommIOService;
    @Value("${jwt.path}")
    private String SECRET_KEY;
    @Autowired
    private SampleScrewMapper sampleScrewMapper;

    // 1. 定义螺丝类型分组常量（提前声明，集中管理硬编码）
    private static final Map<String, List<String>> TYPE_GROUP_MAP = new HashMap<String, List<String>>() {{
        // key: 目标列表标识（对应sampledData0/02/03/04）
        // value: 属于该组的螺丝类型
        put("0", Arrays.asList("screwType1", "screwType5", "screwType9", "screwType13", "screwType17"));
        put("02", Arrays.asList("screwType2", "screwType6", "screwType10", "screwType14", "screwType18"));
        put("03", Arrays.asList("screwType3", "screwType7", "screwType11", "screwType15", "screwType19"));
        put("04", Arrays.asList("screwType4", "screwType8", "screwType12", "screwType16", "screwType20"));
    }};

    private boolean isValidToken(String token) {
//        log.info("token是"+token);
        if (token == null || !token.startsWith("Bearer ")) {
            return false; // 检查令牌格式
        }
        // 提取实际的JWT部分
        token = token.substring(7); // 去掉“Bearer ”前缀
        log.info("token1是"+token);
        try {
            log.info("解析令牌");
            // 解析令牌
            Claims claims = Jwts.parser()
                    .setSigningKey(SECRET_KEY)
                    .setAllowedClockSkewSeconds(300) // 允许5分钟的时钟偏差
                    .parseClaimsJws(token)
                    .getBody();

            // 获取过期时间
            Date expiration = claims.getExpiration();
            log.info("过期时间："+expiration);
            // 检查是否过期
            return expiration != null && expiration.after(new Date());
        } catch (ExpiredJwtException e) {
            // 处理过期令牌的异常
            log.info("令牌已过期: " + e.getMessage());
            return false;
        } catch (SignatureException e) {
            // 处理签名验证失败的异常
            log.info("令牌签名无效: " + e.getMessage());
            return false;
        } catch (Exception e) {
            // 处理其他可能的异常
            log.info("令牌验证失败: " + e.getMessage());
            return false;
        }
    }

    @GetMapping("/checkSampleScrewExist")
    @CrossOrigin
    public ResponseEntity<?> checkSampleScrew() {
        log.info("checkSampleScrew的线程id:{}", Thread.currentThread().getId()+"名"+Thread.currentThread().getName());

        LocalDate today = LocalDate.now();
        LocalDate yesterday = LocalDate.now().minusDays(1);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String yesterdayStr = yesterday.format(formatter);
        String todayStr = today.format(formatter);
        LambdaQueryWrapper<SampleScrew> sampleScrewRepository = new LambdaQueryWrapper<>();
        //System.out.println("yesterdayStr1是"+yesterdayStr);
        //System.out.println("todayStr是"+todayStr);
//        sampleScrewRepository.like(SampleScrew::getScrewCreateTime, yesterdayStr).or()
//                .like(SampleScrew::getCreateTime, todayStr);
        sampleScrewRepository.like(SampleScrew::getCreateTime, todayStr);
        List<SampleScrew> sampleScrews = sampleScrewMapper.selectList(sampleScrewRepository);
//        Optional<SampleScrew> sampleScrew = sampleScrewRepository.findByDate(yesterdayStr);

        LambdaQueryWrapper<Car> queryCarWrapper = new LambdaQueryWrapper<>();

//有歧义，.eq(Car::getCarType, carTypeProperties.getLevin())单独成一个条件了，不正确
//        queryCarWrapper.like(Car::getCreateTime, yesterdayStr);
//        queryCarWrapper.eq(Car::getCarType, carTypeProperties.getCamry()).or()
//                .eq(Car::getCarType, carTypeProperties.getLevin());
        queryCarWrapper.like(Car::getCreateTime, yesterdayStr)
                .and(i -> i.eq(Car::getCarType, carTypeProperties.getCamry())
                        .or()
                        .eq(Car::getCarType, carTypeProperties.getLevin()));
        List<Car> carList = carMapper.selectList(queryCarWrapper);

        List<Long> carIds = carList.stream().map(Car::getId)
                .collect(Collectors.toList());
//        //System.out.println("carIds是：" + carIds);

        List<Screw> screwList = new ArrayList<>();
        if(!carIds.isEmpty()){
            LambdaQueryWrapper<Screw> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(Screw::getCarId, carIds);
            screwList = screwMapper.selectList(wrapper);
        }

//        //System.out.println("screwList是：" + screwList);

        //isPresent() 方法用于检查 Optional 容器中是否包含值。如果存在值，则返回 true，否则返回 false
//        boolean hasData = sampleScrews.isPresent();
//        boolean hasData1 = !sampleScrews.isEmpty();
//        boolean hasData2 = carList.isEmpty();
//        boolean hasData3 = screwList.isEmpty();

//        //System.out.println("sampleScrews1是"+sampleScrews);
//        //System.out.println("carList1是"+carList);
//        //System.out.println("screwList1是"+screwList);
        if (!sampleScrews.isEmpty()) {
            log.info("昨日螺丝数据已取样");
//            if(!carList.isEmpty() && !screwList.isEmpty()){
//                boolean hasData = false;
//                return ResponseEntity.ok().body(Map.of("hasData", hasData));
//            }
            boolean hasData = true;
            return ResponseEntity.ok().body(Map.of("hasData", hasData));
        }else if (carList.isEmpty() || screwList.isEmpty()) {
            log.info("昨日没有相关车型或螺丝数据，无需取样");
            boolean hasData = true;
            return ResponseEntity.ok().body(Map.of("hasData", hasData));
        }
        boolean hasData = false;
        return ResponseEntity.ok().body(Map.of("hasData", hasData));
    }


    @GetMapping("/sampling")
    @CrossOrigin
    @Transactional
    public Result sampling() {
        log.info("sampling的线程id:{}", Thread.currentThread().getId()+"名"+Thread.currentThread().getName());

        // 获取当前日期
        LocalDate today = LocalDate.now();
        // 获取前一日
        LocalDate previousDay = today.minusDays(1);
        // 打印前一日
        log.info("昨日是：" + previousDay);
        //System.out.println("昨日是：" + previousDay);
        String day0 = today.toString();
        String day = previousDay.toString();
        LambdaQueryWrapper<SampleScrew> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(SampleScrew::getCreateTime, day0);
        List<SampleScrew> sampleScrews = sampleScrewMapper.selectList(queryWrapper);
//        //System.out.println("sampleScrews是"+sampleScrews);
        if (!sampleScrews.isEmpty()) {
            log.info("昨日螺丝数据已取样");//是今日取的
            return new Result(Code.SAVE_ERR,  "昨日螺丝数据已取样");
        }
        LambdaQueryWrapper<Car> queryCar0Wrapper = new LambdaQueryWrapper<>();
//有歧义，.eq(Car::getCarType, carTypeProperties.getLevin())单独成一个条件了，不正确
//        queryCar0Wrapper.like(Car::getCreateTime, day);
//        queryCar0Wrapper.eq(Car::getCarType, carTypeProperties.getCamry()).or()
//                .eq(Car::getCarType, carTypeProperties.getLevin());
        queryCar0Wrapper.like(Car::getCreateTime, day)
                .and(i -> i.eq(Car::getCarType, carTypeProperties.getCamry())
                        .or()
                        .eq(Car::getCarType, carTypeProperties.getLevin()));

        List<Car> Cars = carMapper.selectList(queryCar0Wrapper);
        if (Cars.isEmpty()) {
            log.info("昨日没有相关车型数据");
            return new Result(Code.SAVE_ERR,  "昨日车型"+carTypeProperties.getCamry()+"和"
                    +carTypeProperties.getLevin()+"的数据为空，无法取样");
        }else{
            //System.out.println("昨日有相关车型数据");
            List<Long> carIds = Cars.stream().map(Car::getId)
                    .collect(Collectors.toList());
            //System.out.println("carIds是：" + carIds);

            LambdaQueryWrapper<Screw> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(Screw::getCarId, carIds);
            List<Screw> screwList = screwMapper.selectList(wrapper);
            //System.out.println("screwList是：" + screwList);
            if(screwList.isEmpty()){
                log.info("昨日螺丝数据为空");
                return new Result(Code.SAVE_ERR,  "昨日车型"+carTypeProperties.getCamry()+"和"
                        +carTypeProperties.getLevin()+"的螺丝数据为空");
            }
        }
        // 分别处理凯美瑞和雷凌车型
        for (String carType : Arrays.asList(carTypeProperties.getCamry(),
                carTypeProperties.getLevin())) {
            // 查询前一天的特定车型的车辆
            LambdaQueryWrapper<Car> queryCarWrapper = new LambdaQueryWrapper<>();
            queryCarWrapper.like(Car::getCreateTime, day);
            queryCarWrapper.eq(Car::getCarType, carType);
            List<Car> carList = carMapper.selectList(queryCarWrapper);
            //System.out.println("carType是:" + carType);
            //System.out.println("carList.size()是：" + carList.size());
            if (carList.isEmpty()) {
                //System.out.println("没有找到昨天的" + carType + "车型");
                log.info("没有找到昨天的" + carType + "车型");
                continue; // 继续处理下一个车型
            }

            List<Long> carIds = carList.stream().map(Car::getId).toList();

            int batchSize = frequencyProperties.getSampleDataFrequency(); // 每批处理的车辆ID数量
            int totalCars = carIds.size(); // 总车辆数

// 只处理前8批车辆ID，确保不会处理超过前8批的车辆ID(取多一批，防止数据不够)
            for (int i = 0; i < 9; i++) {
                // 计算当前需要处理的车辆ID的索引
                int index = i * batchSize;
                // 确保索引不会超出车辆ID列表的范围
                if (index < totalCars) {
                    Long carId = carIds.get(index);
                    log.info("正在处理车辆ID: " + carId);
                    //System.out.println("正在处理车辆ID: " + carId);
                    // 为当前车辆ID查询对应的螺丝
                    LambdaQueryWrapper<Screw> queryScrewWrapper = new LambdaQueryWrapper<>();
                    queryScrewWrapper.eq(Screw::getCarId, carId);
                    List<Screw> screwList = screwMapper.selectList(queryScrewWrapper);
                    for (Screw screw : screwList) {
                        SampleScrew sampleScrew = new SampleScrew();
                        sampleScrew.setScrewTypeId(screw.getScrewTypeId());
                        sampleScrew.setCarType(carType);
                        sampleScrew.setTorque(screw.getTorque());
                        sampleScrew.setScrewCreateTime(screw.getCreateTime());
                        sampleScrew.setUnit(MessageConstant.torqueUnit);//screw.getUnit()
                        sampleScrewMapper.insert(sampleScrew);//saveBatch
                    }
                } else {
                    // 如果索引超出范围，说明没有足够的车辆ID进行处理
                    log.info("没有足够的车辆ID进行处理");
                    //System.out.println("没有足够的车辆ID进行处理");
                    //break;
                }
            }
        }
        return new Result(Code.SAVE_OK, "昨日螺丝数据取样成功");
    }


    //添加螺丝和告警数据
    @PostMapping("/addScrewData")
    @Transactional//
    @CrossOrigin
    public Result addScrewData(@RequestHeader("Authorization") String Token,
                                  // 从请求头获取令牌
                                  @RequestBody ScrewAddCondition screwAddCondition) {//@Validated
        log.info("添加螺丝信息：{}", screwAddCondition);
        if (!isValidToken(Token)) {
            return new Result(Code.LOGIN_ERR, "无效或过期的令牌");
        }

        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<ScrewAddCondition>> violations = validator.validate(screwAddCondition);

        if (!violations.isEmpty()) {
            StringBuilder errorMessage = new StringBuilder();
            for (ConstraintViolation<ScrewAddCondition> violation : violations) {
                errorMessage.append(violation.getMessage()).append("; ");
            }
            return new Result(Code.UPDATE_ERR, errorMessage.toString());
        }

        //查出是哪辆车的螺丝
        Car car = carMapper.selectById(screwAddCondition.getCarId());
        if(car == null){
            return new Result(Code.SAVE_ERR, "没有找到该车信息");
        }
        //构建螺丝数据
        Screw screw = new Screw();
        CarStatus carStatus = new CarStatus();

        if(screwAddCondition.getScrewTypeId() != null){
           if(screwAddCondition.getScrewTypeId() <= 16){
               screw.setWorkingPositionId(MessageConstant.workingPosition1);
               carStatus.setWorkingPositionId(MessageConstant.workingPosition1);
           } else {
               screw.setWorkingPositionId(MessageConstant.workingPosition2);
               carStatus.setWorkingPositionId(MessageConstant.workingPosition2);
           }
        }
        screw.setScrewTypeId(screwAddCondition.getScrewTypeId());
        carStatus.setScrewTypeId(screwAddCondition.getScrewTypeId());

        screw.setTorque(Double.valueOf(screwAddCondition.getTorque()));
        carStatus.setTorque(Double.valueOf(screwAddCondition.getTorque()));

        screw.setUnit(MessageConstant.torqueUnit);
        carStatus.setUnit(MessageConstant.torqueUnit);

        screw.setCarId(screwAddCondition.getCarId());
        carStatus.setCarId(screwAddCondition.getCarId());

        carStatus.setEmployeeName(screwAddCondition.getEmployeeName());

        screw.setUpdateTime(new Date());
        int x = screwMapper.insert(screw);

//        System.out.println("可以立即获取螺丝Id吗"+screw.getId());

        carStatus.setScrewId(screw.getId());

        //标注它曾经是没有记录到的告警数据,所有告警数据都是danger
        carStatus.setAlarmLevel(CarStatus.AlarmLevel.danger);
        //告警状态，过大过小。。。
        carStatus.setAlarmStatus(CarStatus.AlarmStatus.normal);

        carStatus.setCheckStatus(CarStatus.CheckStatus.Checked);
        carStatus.setUpdateTime(new Date());

        int y = carStatusMapper.insert(carStatus);
        if(x <= 0 || y <= 0){
            return new Result(Code.SAVE_ERR, "螺丝数据添加失败");
        }

//        //1.只统计当天的车的螺丝缺失的空数据数
        int emptyNum = countScrewIsNull();
//        //把需要返回的数据单独储存起来
//        int returnedNum = emptyNum;
        log.info("添加螺丝时，获取到的当天螺丝缺失总数是："+emptyNum);
//        if(emptyNum > 0){
//        }

        //只要添加的螺丝的车是今天的，警告数就要-1
        //如果当前添加的螺丝的车辆是今天的，警告数才需要--，否则不需要
//        Car currentCar = carService.getById(car.getId());
// 将Date转换为LocalDate进行比较
        LocalDate currentCarDate = car.getCreateTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();

        LocalDate today = LocalDate.now();
        System.out.println(currentCarDate + "对比" + today);
        if (currentCarDate.equals(today)) {
            System.out.println("添加的是今天的车的螺丝");
            log.info("添加的是今天的车的螺丝");
            //不用--了，因为刚添加的螺丝在前面的逻辑里就已经插入了，后面才统计缺失数，@Transcational只有在报错时才生效？？？
//                emptyNum--;
//            CacheUtil.putInCache("emptyNum",emptyNum);
            //空螺丝数-1，警告数也-1
            Object alarmsTime = CacheUtil.getFromCache("alarmsTime");
            if(alarmsTime != null){
                int alarmsTimeCount = (Integer) alarmsTime;
                if(alarmsTimeCount > 0){
                    alarmsTimeCount = (Integer) alarmsTime - 1;
                }
                //更新缓存
                CacheUtil.putInCache("alarmsTime", alarmsTimeCount);
                log.info("添加螺丝后，空螺丝+普通警报统计缓存是{}", alarmsTimeCount);
                Map map0 = new HashMap();
                map0.put("alarmsTime",alarmsTimeCount);
                String json = JSON.toJSONString(map0);
                webSocketServer.sendToAllClient(json);
            }
        }else {
            log.info("添加的是非今天的车的螺丝");
            System.out.println("添加的不是今天的车的螺丝");
        }

        if(emptyNum == 0) {
            log.info("可以变绿灯了 emptyNum："+emptyNum);
            jSerialCommIOService.greenUp();
            //和后面的代码重复了
//            car.setScrewIsNull(null);
//            //该车的所有螺丝状态都设为已处理？
//            //？？？？？？
//            carService.updateById(car);
        }
        //只统计当前车辆的螺丝缺失的空数据数
        int emptyNum1 = countScrewIsNull1(car.getId());
//        if(emptyNum1 > 0){
//            emptyNum1--;
//        }
        if(emptyNum1 == 0) {
            //必须当前添加的螺丝的车辆id对应的所有螺丝添加够16粒？20粒？，才能setScrewIsNull(null)
            car.setScrewIsNull(null);
            //该车的所有螺丝状态都设为已处理？
            //？？？？？？
            carService.updateById(car);
        }

        //需要改成数据库最新第一条排除掉，最新第2和3条(最新第3条相当于排除掉工位二的最新第一条了)判16粒就够了，剩下的都要判断20粒


        //.只统计第一次打开软件的累计的空数据数
        //处理完多少个变绿灯
//        Object emptyNum1 = CacheUtil.getFromCache("emptyNum");
//        Object emptyNum2 = CacheUtil.getFromCache("emptyNum2");
//        if(emptyNum1 != null){// && emptyNum2 != null
//            int emptyNum = (int) emptyNum1;// + (int) emptyNum2;
//            log.info("修改螺丝时，获取到的螺丝缺失数是："+emptyNum);
//            if(emptyNum > 0){
//                emptyNum--;
//                CacheUtil.putInCache("emptyNum",emptyNum);
//            }
//            log.info("可以变绿灯？："+emptyNum);
//            if(emptyNum == 0) {
//                jSerialCommIOService.greenUp();
//                car.setScrewIsNull(null);
//                carService.updateById(car);
//            }
//        }
        return new Result(Code.SAVE_OK, emptyNum,"螺丝数据添加成功");
    }

    //未排除掉查到的螺丝是今天的，但是它对应的车不是今天的
//    private int countScrewIsNull() {
//        // 1. 修正：LocalDateTime精度截断（适配MySQL datetime 3位毫秒，避免纳秒解析失败）
//        // 修正：按UTC时间筛选今天（适配create_time存UTC的场景）
////        // 1. 定义当天时间范围（00:00:00 至 23:59:59）
//        LocalDateTime todayStart = LocalDateTime.of(LocalDate.now(), LocalTime.MIN); // 当天开始
//        LocalDateTime todayEnd = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);   // 当天结束
//
//        // 用 CarMapper 查最新3个 id（需确保 CarMapper 存在，且有对应的 LambdaQueryWrapper 方法）
//        LambdaQueryWrapper<Car> carQueryWrapper = new LambdaQueryWrapper<>();
//        // 按 create_time 降序，取前3条，仅查 id 字段
//        carQueryWrapper
//                .orderByDesc(Car::getCreateTime)
//                .last("LIMIT 3") // MySQL 语法，Oracle 改 "WHERE rownum <=3"，SQL Server 改 "TOP 3"
//                .select(Car::getId);
//        List<Car> latest3Car = carMapper.selectList(carQueryWrapper);
//
//        List<Long> latest3CarIds = latest3Car.stream().map(Car::getId).collect(Collectors.toList());
//
//        // 执行查询，得到最新3个 car 的 id 列表（List<Long>，按需调整类型）
//
//// 替换后的Lambda版本代码段
//        QueryWrapper<Screw> queryWrapper = new QueryWrapper<>();
//
//        //失败
////        // 子查询保持不变（跨表car表，无Lambda，无外层括号、无别名）
////        String latest3CarSubQuery =
////                "SELECT id " + // car表主键id，关联screw.car_id
////                        "FROM car " +
////                        "ORDER BY create_time DESC " +
////                        "LIMIT 3";
//
//        // 查询时用UTC时间筛选
//        queryWrapper
//                .ge("create_time", todayStart)
//                .le("create_time", todayEnd);
//
//        queryWrapper
////                // 原有：筛选当天数据
////                .ge("create_time", todayStart)
////                .le("create_time", todayEnd)
//                // 核心：排除car表最新3个car的所有螺丝
////                .notIn("car_id", latest3CarIds)
//                // 原有：按car_id分组统计
//                .select("car_id", "count(*) as countNum")
//                .groupBy("car_id");
//
//        // 第一部分 queryWrapper 增加：若 latest3CarIds 为空，不执行 notIn
//        if (!latest3CarIds.isEmpty()) {
//            queryWrapper.notIn("car_id", latest3CarIds);
//        }
//
//// 执行查询（返回结果格式与原QueryWrapper一致）
//        List<Map<String, Object>> carScrewCountList = screwMapper.selectMaps(queryWrapper);
//        // 修正2：增加空指针防护（避免无数据时NPE）
//        int totalMissing = 0;
//        if (carScrewCountList != null && !carScrewCountList.isEmpty()) {
//            for (Map<String, Object> countMap : carScrewCountList) {
//                Long actualCount = (Long) countMap.getOrDefault("countNum", 0L); // 兜底0，避免null
//                int missing = Math.max(0, 20 - actualCount.intValue());
//                totalMissing += missing;
//            }
//        }
//
//        log.info("排除前3条Car后螺丝缺失数：" + totalMissing);
//        System.out.println("排除前3条Car后螺丝缺失数：" + totalMissing);
//
//        // ====================== 第二部分：统计「最新3条中第2、3条car」的缺失数（按16粒标准）======================
//        QueryWrapper<Screw> queryWrapper1 = new QueryWrapper<>();
//
//        // 筛选最新3条中「第2、3条」的ID列表（用于第二部分统计）
//        List<Long> targetCarIds = new ArrayList<>();
//        if (latest3Car.size() >= 2) {
//            // 索引1=第2条，索引2=第3条（列表是降序，索引0是最新第1条）
//            targetCarIds = latest3Car.subList(1, Math.min(latest3Car.size(), 3)) // 避免不足3条时报错
//                    .stream()
//                    .map(Car::getId)
//                    .collect(Collectors.toList());
//        }
//
//        queryWrapper1
////                .ge("create_time", todayStart)
////                .le("create_time", todayEnd)
//                // 查询时用UTC时间筛选
//                .ge("create_time", todayStart)
//                .le("create_time", todayEnd)
////                .in("car_id", targetCarIds) // 用筛选后的ID列表替代inSql，无报错
//                .select("car_id", "count(*) as countNum1")
//                .groupBy("car_id");
//
//        List<Map<String, Object>> carScrewCountList1;
//        System.out.println("targetCarIds是：" + targetCarIds);
//        // 第二部分 queryWrapper1 增加：若 targetCarIds 为空，不执行 in
//        if (!targetCarIds.isEmpty()) {
//            queryWrapper1.in("car_id", targetCarIds);
//            carScrewCountList1 = screwMapper.selectMaps(queryWrapper1);
//        } else {
//            // 无目标ID时，直接返回空结果（避免无效查询）
//            carScrewCountList1 = new ArrayList<>();
//        }
//
//
//        // 修正2：增加空指针防护
//        if (carScrewCountList1 != null && !carScrewCountList1.isEmpty()) {
//            for (Map<String, Object> countMap : carScrewCountList1) {
//                Long actualCount = (Long) countMap.getOrDefault("countNum1", 0L); // 兜底0，避免null
//                int missing = Math.max(0, 16 - actualCount.intValue());
//                totalMissing += missing;
//            }
//        }
//
//        log.info("当天螺丝总缺失数：" + totalMissing);
//        System.out.println("当天螺丝总缺失数：" + totalMissing);
//
//        return totalMissing;
//    }

    private int countScrewIsNull1(Long carId) {
        // 1. 处理carId为null的边界情况（避免空指针）
        if (carId == null) {
            log.warn("传入的车辆ID（carId）为null，螺丝缺失数：0");
            System.out.println("传入的车辆ID（carId）为null，螺丝缺失数：0");
            return 0;
        }
        // 2. 关键新增：查询数据库中「最新创建的3条Car记录」（按创建时间降序）
        LambdaQueryWrapper<Car> latest3CarQuery = new LambdaQueryWrapper<>();
        latest3CarQuery.orderByDesc(Car::getCreateTime) // 按创建时间倒序（最新的在前）
                .last("LIMIT 3") // 只取前3条
                .select(Car::getId); // 仅查询ID字段，提高效率
        List<Car> latest3Cars = carMapper.selectList(latest3CarQuery);

        // 3. 提取最新3条Car的ID列表（用于判断目标车辆是否在其中）
        List<Long> latest3CarIds = latest3Cars.stream()
                .map(Car::getId)
                .toList();

        // 4. 动态确定标准粒数：在最新3条中→16粒，否则→20粒
        int standardCount = latest3CarIds.contains(carId) ? 16 : 20;

        // 5. 统计目标车辆的螺丝总数（原有逻辑不变）
        LambdaQueryWrapper<Screw> screwQuery = new LambdaQueryWrapper<>();
        screwQuery.eq(Screw::getCarId, carId);
        int actualCount = screwMapper.selectCount(screwQuery);

        // 6. 计算缺失数（确保非负）
        int totalMissing = Math.max(0, standardCount - actualCount);

        // 7. 日志优化：补充标准粒数和车辆是否在最新3条的信息
        log.info("当前处理车辆（ID：{}）- 是否在最新3条Car中：{}，标准粒数：{}粒，实际粒数：{}粒，缺失数：{}粒",
                carId, latest3CarIds.contains(carId), standardCount, actualCount, totalMissing);
        System.out.printf("当前处理车辆（ID：%d）- 标准粒数：%d粒，实际粒数：%d粒，缺失数：%d粒%n",
                carId, standardCount, actualCount, totalMissing);

        return totalMissing;
    }

    private int countScrewIsNull() {
        // 1. 时间处理：统一按「本地时间」筛选今天（若Car/Screw的create_time存UTC，需改为UTC时间，见注释）
        LocalDate today = LocalDate.now();
        // 本地时间：今天00:00:00.000（若存UTC，需 minusHours(8) 转换）
        LocalDateTime todayStart = LocalDateTime.of(today, LocalTime.MIN);
        // 本地时间：今天23:59:59.999（若存UTC，需 minusHours(8) 转换）
        LocalDateTime todayEnd = LocalDateTime.of(today, LocalTime.of(23, 59, 59, 999_000_000));

        // ====================== 关键新增：查询「今天创建的所有Car的ID列表」（用于过滤螺丝对应的车）======================
        LambdaQueryWrapper<Car> todayCarQueryWrapper = new LambdaQueryWrapper<>();
        todayCarQueryWrapper
                .ge(Car::getCreateTime, todayStart) // Car的创建时间是今天
                .le(Car::getCreateTime, todayEnd)
                .select(Car::getId);
        List<Car> todayCars = carMapper.selectList(todayCarQueryWrapper);
        List<Long> todayCarIds = todayCars.stream()
                .map(Car::getId)
                .collect(Collectors.toList());

        // 若今天没有创建任何Car，直接返回0（无需后续查询）
        if (todayCarIds.isEmpty()) {
            log.info("今天无创建的Car，螺丝缺失数：0");
            System.out.println("今天无创建的Car，螺丝缺失数：0");
            return 0;
        }

        // ====================== 预查询：Car表最新3条记录（无论是否今天，用于排除和统计第2、3条）======================
        LambdaQueryWrapper<Car> carQueryWrapper = new LambdaQueryWrapper<>();
        carQueryWrapper
                .orderByDesc(Car::getCreateTime)
                .last("LIMIT 3")
                .select(Car::getId);
        List<Car> latest3Car = carMapper.selectList(carQueryWrapper);
        List<Long> latest3CarIds = latest3Car.stream()
                .map(Car::getId)
                .collect(Collectors.toList());

        // ====================== 第一部分：排除最新3条Car，仅统计「今天的螺丝+今天的车」（20粒标准）======================
        QueryWrapper<Screw> queryWrapper = new QueryWrapper<>();
        queryWrapper
                // 1. 螺丝是今天的
                .ge("create_time", todayStart)
                .le("create_time", todayEnd)
                // 2. 螺丝对应的车是今天创建的（核心新增筛选）
                .in("car_id", todayCarIds)
                // 3. 排除最新3条Car
                .select("car_id", "count(*) as countNum")
                .groupBy("car_id");

        // 动态添加排除条件（避免空列表）
        if (!latest3CarIds.isEmpty()) {
            queryWrapper.notIn("car_id", latest3CarIds);
        }

        List<Map<String, Object>> carScrewCountList = screwMapper.selectMaps(queryWrapper);
        int totalMissing = 0;
        // 计算第一部分缺失数
        if (carScrewCountList != null && !carScrewCountList.isEmpty()) {
            for (Map<String, Object> countMap : carScrewCountList) {
                Long actualCount = (Long) countMap.getOrDefault("countNum", 0L);
                totalMissing += Math.max(0, 20 - actualCount.intValue());
            }
        }
        log.info("排除前3条Car后，今天螺丝（对应车也是今天）缺失数：{}", totalMissing);
        System.out.println("排除前3条Car后，今天螺丝（对应车也是今天）缺失数：" + totalMissing);

        // ====================== 第二部分：统计「最新3条中第2、3条+今天的车」的缺失数（16粒标准）======================
        QueryWrapper<Screw> queryWrapper1 = new QueryWrapper<>();
        // 筛选：最新3条中第2、3条 + 同时是今天创建的Car（核心过滤非今天的车）
        List<Long> targetCarIds = new ArrayList<>();
        if (latest3Car.size() >= 2) {
            targetCarIds = latest3Car.subList(1, Math.min(latest3Car.size(), 3))
                    .stream()
                    .map(Car::getId)
                    // 仅保留「今天创建的Car」的ID（排除非今天的车）
                    .filter(todayCarIds::contains)
                    .collect(Collectors.toList());
        }

        queryWrapper1
                // 1. 螺丝是今天的
                .ge("create_time", todayStart)
                .le("create_time", todayEnd)
                // 2. 螺丝对应的车是今天创建的
                .in("car_id", todayCarIds);

        List<Map<String, Object>> carScrewCountList1;
        if (!targetCarIds.isEmpty()) {
            queryWrapper1
                    .in("car_id", targetCarIds) // 3. 仅统计最新2、3条今天的车
                    .select("car_id", "count(*) as countNum1")
                    .groupBy("car_id");
            carScrewCountList1 = screwMapper.selectMaps(queryWrapper1);
        } else {
            carScrewCountList1 = new ArrayList<>();
        }

        // 计算第二部分缺失数
        if (carScrewCountList1 != null && !carScrewCountList1.isEmpty()) {
            for (Map<String, Object> countMap : carScrewCountList1) {
                Long actualCount = (Long) countMap.getOrDefault("countNum1", 0L);
                totalMissing += Math.max(0, 16 - actualCount.intValue());
            }
        }

        log.info("当天螺丝总缺失数（仅统计今天的螺丝+今天的车）：{}", totalMissing);
        System.out.println("当天螺丝总缺失数（仅统计今天的螺丝+今天的车）：" + totalMissing);

        return totalMissing;
    }

    //统计当天所有车辆的缺少的螺丝数
//    private int countScrewIsNull() {
//        // 1. 定义当天时间范围（00:00:00 至 23:59:59）
//        LocalDateTime todayStart = LocalDateTime.of(LocalDate.now(), LocalTime.MIN); // 当天开始
//        LocalDateTime todayEnd = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);   // 当天结束
//
//// 2. 构建查询条件：筛选当天数据，按carId分组，统计每个carId的螺丝数量
////        LambdaQueryWrapper<Screw> queryWrapper = new LambdaQueryWrapper<>();
////        queryWrapper
////                // 筛选当天的螺丝记录
////                .ge(Screw::getCreateTime, todayStart)
////                .le(Screw::getCreateTime, todayEnd)
////                // 按carId分组，并统计每个组的数量（别名countNum）
////                MyBatis-Plus 版本较旧（比如 3.0.x 及以下），
////                可能不支持LambdaQueryWrapper的select方法混合 Lambda 和字符串
////                .select(Screw::getCarId, "count(*) as countNum")
////                .groupBy(Screw::getCarId);
//
//        // 改用QueryWrapper（非Lambda版本）
////        QueryWrapper<Screw> queryWrapper = new QueryWrapper<>();
////        queryWrapper
////                // 筛选当天数据（注意：这里使用数据库列名，而非实体类方法）
////                .ge("create_time", todayStart)  // 假设实体类Screw的createTime对应数据库列名是create_time
////                .le("create_time", todayEnd)
////                // 按carId分组，统计数量（直接写SQL片段）
////                .select("car_id", "count(*) as countNum")  // car_id对应实体类的carId字段
////                .groupBy("car_id");
//
//        //新新逻辑
//        //1.通过子查询获取 car 表中最新的 3 个 car_id（按 car 表的时间字段降序取前 3），
//        // 再在主查询中排除这 3 个 car_id 对应的所有当天螺丝
//        QueryWrapper<Screw> queryWrapper = new QueryWrapper<>();
//
//// 1. 子查询：获取 car表最新的3个car_id（按car表create_time降序）
//        String latest3CarSubQuery = "(" +
//                "SELECT car_id " +
//                "FROM car " + // 目标表：car表（存储car的最新状态）
//                "ORDER BY create_time DESC " + // 按car表的时间字段降序（确保取最新）
//                "LIMIT 3" + // 取前3条（最新3个car）
//                ") AS latest_cars";
//
//// 2. 主查询：保留原有逻辑 + 排除最新3个car_id
//        queryWrapper
//                // 原有：筛选当天数据
//                .ge("create_time", todayStart)
//                .le("create_time", todayEnd)
//                // 核心：排除car表最新3个car的所有螺丝
//                .notInSql("car_id", latest3CarSubQuery)
//                // 原有：按car_id分组统计
//                .select("car_id", "count(*) as countNum")
//                .groupBy("car_id");
//
//// 3. 执行查询，获取除了前3条每个carId对应的螺丝数量（返回结果为Map列表，key为字段名）
//        List<Map<String, Object>> carScrewCountList = screwMapper.selectMaps(queryWrapper);
//
//// 4. 计算总缺失数量
//        int totalMissing = 0;
//        for (Map<String, Object> countMap : carScrewCountList) {
//            // 获取当前carId的螺丝实际数量（count(*)返回Long类型）
//            Long actualCount = (Long) countMap.get("countNum");
//            // 计算单车辆缺失数量（不足20则补差额，否则为0）写16是排除掉工位二的
//            int missing = Math.max(0, 20 - actualCount.intValue());
//            // 累加总缺失
//            totalMissing += missing;
//        }
//
//        //--------------------------------
//        //2再单独把刚才排除掉的三条car记录的最新第2和第3条对应的所有螺丝找出来
//        QueryWrapper<Screw> queryWrapper1 = new QueryWrapper<>();
//        // 1. 子查询：锁定car表最新3条中「第2、3条」的car_id（打序号精准筛选）
//        // 1. 子查询：获取 car表最新的3个car_id（逻辑不变，正确）
////        String latest3CarSubQuery = "(" +
////                "SELECT car_id " +
////                "FROM car " + // 目标表：car表（存储car的最新状态）
////                "ORDER BY create_time DESC " + // 按car表时间降序取最新
////                "LIMIT 3" + // 取前3条（最新3个car）
////                ") AS latest_cars";
//
//// 2. 主查询：修正 inSql 方法名大小写，其余逻辑不变
//        queryWrapper1
//                // 原有：筛选当天数据（正确）
//                .ge("create_time", todayStart)
//                .le("create_time", todayEnd)
//                // 核心修正：InSql → inSql（MyBatis-Plus 方法名是小写i）
//                .inSql("car_id", latest3CarSubQuery)
//                // 原有：按car_id分组统计（正确）
//                .select("car_id", "count(*) as countNum1")
//                .groupBy("car_id");
//        // 3. 执行查询，获取前3条每个carId对应的螺丝数量（16颗）（返回结果为Map列表，key为字段名）
//        List<Map<String, Object>> carScrewCountList1 = screwMapper.selectMaps(queryWrapper1);
//
//        // 4. 单独计算car表前三条car记录所对应的所有缺失数量
//        for (Map<String, Object> countMap : carScrewCountList1) {
//            // 获取当前carId的螺丝实际数量（count(*)返回Long类型）
//            Long actualCount = (Long) countMap.get("countNum1");
//            // 计算单车辆缺失数量（不足16则补差额，否则为0）
//            int missing = Math.max(0, 16 - actualCount.intValue());
//            // 继续累加总缺失
//            totalMissing += missing;
//        }
//
//        //--------------------------
//// 最终结果：当天所有车辆的螺丝缺失总数
//        System.out.println("当天螺丝总缺失数：" + totalMissing);
//        return totalMissing;
//    }


    //修改螺丝扭力数据
    @PostMapping("/updateScrewData")
    @Transactional
    @CrossOrigin
    public Result updateScrewData(@RequestHeader("Authorization") String Token,
             // 从请求头获取令牌
            @RequestBody ScrewUpdateCondition screwUpdateCondition) {//@Validated
        log.info("updateScrewData的线程id:{}", Thread.currentThread().getId()+"名"+Thread.currentThread().getName());
        log.info("修改螺丝信息：{}",screwUpdateCondition);
        //System.out.println("修改螺丝信息：{}"+screwUpdateCondition);
//        //测试红灯缓存
//        //红灯缓存-1
//        Object object0 = CacheUtil.getFromCache("redLight");
////                    List<Long> redLight = new ArrayList<>();
//        if(object0!=null){//有红灯缓存，减1个
//            List<Long> redLight = (List<Long>) object0;
//            //System.out.println("redLight前"+redLight);
//            redLight.remove(screwUpdateCondition.getScrewId());
//            //System.out.println("redLight后"+redLight);
//            CacheUtil.putInCache("redLight",redLight);
////                        redLight.clear();
//            //如果减到0，红灯灭
//            if(redLight.isEmpty()){
//                //System.out.println("红灯处理王城");
//                jSerialCommIOService.greenUp();
//            }
//            return new Result(Code.UPDATE_OK, "红灯处理");
//        }


        //--------------------------------
        // 验证令牌
        if (!isValidToken(Token)) {
            return new Result(Code.LOGIN_ERR, "无效或过期的令牌");
        }

//        if(screwUpdateCondition.getTorque() == null){
//            return new Result(Code.UPDATE_ERR, "请输入扭力值");
//        }

        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<ScrewUpdateCondition>> violations = validator.validate(screwUpdateCondition);

        if (!violations.isEmpty()) {
            StringBuilder errorMessage = new StringBuilder();
            for (ConstraintViolation<ScrewUpdateCondition> violation : violations) {
                errorMessage.append(violation.getMessage()).append("; ");
            }
            return new Result(Code.UPDATE_ERR, errorMessage.toString());
        }

//        LambdaQueryWrapper<Screw> screwQueryWrapper = new LambdaQueryWrapper<>();
//        screwQueryWrapper.eq(Screw::getId, screwUpdateCondition.getScrewId());

//        screwQueryWrapper.eq(Screw::getWorkingPositionId, screwUpdateCondition.getWorkingPositionId());
//        screwQueryWrapper.eq(Screw::getWeldingGunId, screwUpdateCondition.getWeldingGunId());
//        screwQueryWrapper.eq(Screw::getScrewId, screwUpdateCondition.getScrewId());
//        Screw screw = screwService.getOne(screwQueryWrapper);

        Screw screw = screwService.getById(screwUpdateCondition.getScrewId());
        if (screw == null) {
            log.info("该螺丝不存在：{}", screw);
            return new Result(Code.UPDATE_ERR, "该螺丝不存在");
        }

        screw.setTorque(Double.valueOf(screwUpdateCondition.getTorque()));
        screw.setUpdateTime(new Date());
        boolean i = screwService.updateById(screw);
        Map map = new HashMap();
        Map map0 = new HashMap();
        //只要他修改了就把该螺丝的警报改为已处理
        LambdaQueryWrapper<CarStatus> carStatusLambdaQueryWrapper = new LambdaQueryWrapper<>();
        //ScrewId应该是数据库自生成的，唯一的
        carStatusLambdaQueryWrapper.eq(CarStatus::getScrewId, screwUpdateCondition.getScrewId());
//                carStatusLambdaQueryWrapper.eq(CarStatus::getCarId, car.getId());
//                carStatusLambdaQueryWrapper.eq(CarStatus::getWorkingPositionId, screw.getWorkingPositionId());
//                carStatusLambdaQueryWrapper.eq(CarStatus::getWeldingGunId, screw.getWeldingGunId());
//                carStatusLambdaQueryWrapper.eq(CarStatus::getScrewId, screw.getScrewId());

        Integer count = carStatusMapper.selectCount(carStatusLambdaQueryWrapper);
        CarStatus carStatus = null;
        if (count > 1) {
            log.info("该螺丝有多个报警状态");
//            carStatusLambdaQueryWrapper.last("limit 1");
            //删除多余的，只留下一个
            // 查询符合条件的所有记录
            List<CarStatus> list = carStatusService.list(carStatusLambdaQueryWrapper);
            // 保留 list 中的第一条记录，其他的删除
            // 确保保留的记录是否正确
            CarStatus recordToKeep = list.get(0);
            // 删除多余的记录
            for (CarStatus a : list) {
                if (!a.equals(recordToKeep)) {
                    carStatusService.removeById(a.getId());
                }
            }
        }else if (count == 1) {
            carStatus = carStatusService.getOne(carStatusLambdaQueryWrapper);
        }

        if (carStatus != null) {
            //当前修改的螺丝警报之前必须是未处理的，ng的，今天的才能修改铃铛缓存
            LocalDate today = LocalDate.now();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            String todayStr = today.format(formatter);

            // 定义目标格式
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 格式化日期（注意：SimpleDateFormat非线程安全，建议每次使用时新建实例）
            String formattedDate = "";
            if (carStatus.getCreateTime() != null) {
                formattedDate = sdf.format(carStatus.getCreateTime());
            }

            log.info("carStatus是{},todayStr是{},createTime是{}",carStatus,todayStr,formattedDate);
            if(carStatus.getCheckStatus().equals(CarStatus.CheckStatus.waitForCheck)
            && carStatus.getAlarmLevel().equals(CarStatus.AlarmLevel.danger)
            && formattedDate.equals(todayStr)
            ) {
                sendAlarmsTime(todayStr);
            }
//                    carStatus.setAlarmLevel(CarStatus.AlarmLevel.normal);
//                    carStatus.setAlarmStatus(CarStatus.AlarmStatus.normal);
            carStatus.setCheckStatus(CarStatus.CheckStatus.Checked);
            log.info("更新处理时间");
            carStatus.setUpdateTime(new Date());
            if(!screwUpdateCondition.getEmployeeName().isEmpty()){
                carStatus.setEmployeeName(screwUpdateCondition.getEmployeeName());
                LambdaQueryWrapper<Employee> employeeLambdaQueryWrapper = new LambdaQueryWrapper<>();
                employeeLambdaQueryWrapper.eq(Employee::getEmployeeName, screwUpdateCondition.getEmployeeName());
                Employee employee = employeeMapper.selectOne(employeeLambdaQueryWrapper);
                employee.setUpdateTime(new Date());
                //更新处理人的时间
                employeeMapper.updateById(employee);
            }
            carStatusService.updateById(carStatus);

        }

        LambdaQueryWrapper<Car> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Car::getId, screw.getCarId());
        Integer carCount = carMapper.selectCount(queryWrapper);
        Car car = null;
        if(carCount == 1) {
            car = carService.getOne(queryWrapper);
        } else if (carCount > 1) {
            return new Result(Code.UPDATE_ERR, "修改失败，存在多个车辆信息");
        }else {
            return new Result(Code.UPDATE_ERR, "修改失败，该车辆不存在");
        }
        LambdaQueryWrapper<TorqueStandards> torqueStandardsLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (car != null) {
            torqueStandardsLambdaQueryWrapper.eq(TorqueStandards::getCarType, car.getCarType());
        }

        Screw screw0 = screwService.getById(screwUpdateCondition.getScrewId());
        screwType screwType = screwTypeMapper.selectById(screw0.getScrewTypeId());
//不是new一个缓存，而是修改原来的缓存
        //        ScrewIdAndTorqueCache homeCache = new ScrewIdAndTorqueCache();
        //---------------测试------------------
//        ScrewIdAndTorqueCache homeCacher = new ScrewIdAndTorqueCache();
//        homeCacher.setScrewTypeId(screwType.getId());
//        homeCacher.setScrewId(screw.getId());
//        homeCacher.setTorque(88888.0);
//        homeCacher.setStatus(String.valueOf(CarStatus.AlarmStatus.normal));
//        CacheUtil.putInCache("screw" + screwType.getId(), homeCacher);
        //--------------
        Object homeCache0 =
                CacheUtil.getFromCache("screw" + screwType.getId());
        //System.out.println("homeCache0是"+homeCache0);
        ScrewIdAndTorqueCache homeCache = null;
//        int homeCache;
        if(homeCache0!=null) {
            homeCache = (ScrewIdAndTorqueCache) homeCache0;
//            homeCache = (int) homeCache0;
            //System.out.println("homeCache是"+homeCache);
        }
        //判断修改的是车身还是车头
        if (screw.getWorkingPositionId().equals(MessageConstant.workingPosition1)) {
            torqueStandardsLambdaQueryWrapper.eq(TorqueStandards::getWorkingPositionId, MessageConstant.workingPosition1);
            TorqueStandards torqueStandards = torqueStandardsMapper.selectOne(torqueStandardsLambdaQueryWrapper);

            if (screw.getTorque() > torqueStandards.getMaximumTorque() ||
                    screw.getTorque() < torqueStandards.getMinimumTorque()) {
                log.info("扭力不符合标准");
//                homeCache.setStatus("0");
                map.put("status", "0");

                //把map转为json
                String json = JSON.toJSONString(map0);
                log.info("json推警报数消息:"+json);
                webSocketServer.sendToAllClient(json);//推消息

                //修改缓存
//                Screw screw0 = screwService.getById(screwUpdateCondition.getScrewId());
//                screwType screwType = screwTypeMapper.selectById(screw0.getScrewTypeId());

//                Object cache0 = CacheUtil.getFromCache("screw" + screwType.getId());
//                log.info("跟新前的缓存"+cache0);

                if(homeCache0!=null){
//                    ScrewIdAndTorqueCache homeCache = (ScrewIdAndTorqueCache) homeCache0;
                    homeCache.setStatus("0");
                    homeCache.setScrewTypeId(screwType.getId());
                    homeCache.setScrewId(screw0.getId());
                    homeCache.setTorque(Double.valueOf(screwUpdateCondition.getTorque()));
                    CacheUtil.putInCache("screw" + screwType.getId(), homeCache);
                }


//                Object cache = CacheUtil.getFromCache("screw" + screwType.getId());
//                log.info("跟新后的缓存"+cache);

//                jSerialCommIOService.redUp();
                return new Result(Code.UPDATE_OK, map,"扭力不符合标准");
            }else if (screw.getTorque() < torqueStandards.getMaximumTorque() &&
                    screw.getTorque() > torqueStandards.getMinimumTorque() ||
                    screw.getTorque().equals(torqueStandards.getMaximumTorque()) ||
                    screw.getTorque().equals(torqueStandards.getMinimumTorque())) {
                //System.out.println("扭力符合标准");
                if(homeCache0!=null) {
//                    ScrewIdAndTorqueCache homeCache = (ScrewIdAndTorqueCache) homeCache0;
                    homeCache.setStatus("1");
                }
                log.info("扭力符合标准");
                map.put("status", "1");
                map.put("torque", screw.getTorque());
                if (car != null && car.getPendingAlarmCount() > 0) {
                    car.setPendingAlarmCount(car.getPendingAlarmCount() - 1);//待处理告警数-1
                }
                if (car != null) {
                    car.setSolvedAlarmCount(car.getSolvedAlarmCount()+1);//已处理告警数+1
                }
//                if(screwUpdateCondition.getPage() == 1){//只有主页才能处理红灯
                    //红灯缓存-1
                    Object object = CacheUtil.getFromCache("redLight");
//                    List<Long> redLight = new ArrayList<>();
                    if(object!=null){//有红灯缓存，减1个
                        List<Long> redLight = (List<Long>) object;
                        //System.out.println("redLight前"+redLight);
                        redLight.remove(screw.getId());
                        //System.out.println("redLight后"+redLight);
                        CacheUtil.putInCache("redLight",redLight);
//                        redLight.clear();
                        //如果减到0，红灯灭
                        if(redLight.isEmpty()){
                            jSerialCommIOService.greenUp();
                        }
//                    }

                }
            }
        }else if (screw.getWorkingPositionId().equals(MessageConstant.workingPosition2)) {
            torqueStandardsLambdaQueryWrapper.eq(TorqueStandards::getWorkingPositionId, MessageConstant.workingPosition2);
            TorqueStandards torqueStandards = torqueStandardsMapper.selectOne(torqueStandardsLambdaQueryWrapper);

            if (screw.getTorque() > torqueStandards.getMaximumTorque() ||
                    screw.getTorque() < torqueStandards.getMinimumTorque()) {
                //System.out.println("扭力不符合标准");

//                homeCache.setStatus("0");
                map.put("status", "0");
                map.put("torque", screw.getTorque());

                //把map转为json
                String json = JSON.toJSONString(map0);
                log.info("json推警报数消息:"+json);
                webSocketServer.sendToAllClient(json);//推消息

                //修改缓存
//                Screw screw0 = screwService.getById(screwUpdateCondition.getScrewId());
//                screwType screwType = screwTypeMapper.selectById(screw0.getScrewTypeId());

//                Object cache0 = CacheUtil.getFromCache("screw" + screwType.getId());
//                log.info("跟新前的缓存"+cache0);
                if(homeCache0!=null) {
//                    ScrewIdAndTorqueCache homeCache = (ScrewIdAndTorqueCache) homeCache0;
                    homeCache.setStatus("0");
                    homeCache.setScrewTypeId(screwType.getId());
                    homeCache.setScrewId(screw0.getId());
                    homeCache.setTorque(Double.valueOf(screwUpdateCondition.getTorque()));
                    CacheUtil.putInCache("screw" + screwType.getId(), homeCache);
                }

//                Object cache = CacheUtil.getFromCache("screw" + screwType.getId());
//                log.info("跟新后的缓存"+cache);

//                jSerialCommIOService.redUp();
                return new Result(Code.UPDATE_OK, map,"扭力不符合标准");
            }else if (screw.getTorque() < torqueStandards.getMaximumTorque() &&
                    screw.getTorque() > torqueStandards.getMinimumTorque() ||
                    screw.getTorque().equals(torqueStandards.getMaximumTorque()) ||
                    screw.getTorque().equals(torqueStandards.getMinimumTorque())) {
                //System.out.println("扭力符合标准");
                if(homeCache0!=null) {
//                    ScrewIdAndTorqueCache homeCache = (ScrewIdAndTorqueCache) homeCache0;
                    homeCache.setStatus("1");
                }
                map.put("status", "1");
                map.put("torque", screw.getTorque());
                if (car != null && car.getPendingAlarmCount() > 0) {
                    car.setPendingAlarmCount(car.getPendingAlarmCount() - 1);//待处理告警数-1
                }
                if (car != null) {
                    car.setSolvedAlarmCount(car.getSolvedAlarmCount()+1);//已处理告警数+1
                }
//                if(screwUpdateCondition.getPage() == 1){//只有主页才能处理红灯
                    //红灯缓存-1
                    Object object = CacheUtil.getFromCache("redLight");
//                    List<Long> redLight = new ArrayList<>();
                    if(object!=null){//有红灯缓存，减1个
                        List<Long> redLight = (List<Long>) object;
                        //System.out.println("redLight前"+redLight);
                        redLight.remove(screw.getId());
//                        redLight.remove(Long.valueOf(212));
                        //System.out.println("redLight后"+redLight);
                        CacheUtil.putInCache("redLight",redLight);
                        //如果减到0，红灯灭
                        if(redLight.isEmpty()){
                            jSerialCommIOService.greenUp();
                        }
                    }
//                    jSerialCommIOService.greenUp();
//                }

            }
        }

//        LambdaQueryWrapper<CarStatus> wrapper = new LambdaQueryWrapper<>();
//        //匹配扭力不是正常的以及是待处理的告警
//        wrapper.ne(CarStatus::getAlarmStatus, CarStatus.AlarmStatus.normal)
//                .eq(CarStatus::getCheckStatus, CarStatus.CheckStatus.waitForCheck);
//        int alarmsTime = carStatusMapper.selectCount(wrapper);
//        log.info("alarmsTime是"+alarmsTime);
//        if(alarmsTime > 0){
//            map0.put("alarmsTime", alarmsTime - 1);
//        }else{
//            map0.put("alarmsTime", alarmsTime);
//        }
////        Object alarmsTime = CacheUtil.getFromCache("alarmsTime");
////        if (alarmsTime != null) {
////            int alarmsTime1 = (int) alarmsTime;
////
////            // 检查当前值是否大于 0
////            if (alarmsTime1 > 0) {
////                alarmsTime1--;  // 减一
////                CacheUtil.putInCache("alarmsTime", alarmsTime1); // 更新缓存
////                map0.put("alarmsTime", alarmsTime1); // 更新地图
////            }
////        }
//        //把map转为json
//        String json = JSON.toJSONString(map0);
//        log.info("json推警报数消息:"+json);
//        webSocketServer.sendToAllClient(json);//推消息

        //修改缓存

//        Screw screw0 = screwService.getById(screwUpdateCondition.getScrewId());
//        screwType screwType = screwTypeMapper.selectById(screw0.getScrewTypeId());

//        Object cache0 = CacheUtil.getFromCache("screw" + screwType.getId());
//        log.info("跟新前的缓存"+cache0);
        if(homeCache0!=null) {
//            ScrewIdAndTorqueCache homeCache = (ScrewIdAndTorqueCache) homeCache0;
            homeCache.setScrewTypeId(screwType.getId());
            homeCache.setScrewId(screw0.getId());
            homeCache.setTorque(Double.valueOf(screwUpdateCondition.getTorque()));
            CacheUtil.putInCache("screw" + screwType.getId(), homeCache);
        }

//        Object cache = CacheUtil.getFromCache("screw" + screwType.getId());
//        log.info("跟新后的缓存"+cache);


        boolean j = carService.updateById(car);
        if (i && j) {
            return new Result(Code.UPDATE_OK, map,"螺丝信息修改成功");
        } else {
            return new Result(Code.UPDATE_ERR, "螺丝信息修改失败");
        }
    }

    @Async
    public void sendAlarmsTime(String todayStr){
        Map map0 = new HashMap();
        LambdaQueryWrapper<CarStatus> queryWrapper = new LambdaQueryWrapper<>();
        //匹配扭力不是正常的以及是待处理的告警
        queryWrapper.ne(CarStatus::getAlarmLevel, CarStatus.AlarmLevel.normal)
                .eq(CarStatus::getCheckStatus, CarStatus.CheckStatus.waitForCheck);
        //只匹配今天的
//        LocalDate today = LocalDate.now();
//        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
//        String todayStr = today.format(formatter);
        queryWrapper.like(CarStatus::getCreateTime, todayStr);
        int alarmsTime = carStatusMapper.selectCount(queryWrapper);
        log.info("alarmsTime是"+alarmsTime);
        //System.out.println("alarmsTime是"+alarmsTime);
        if(alarmsTime > 0){
            alarmsTime = alarmsTime - 1;//数据库已经少了，不用再减一了，还没少，因为这个方法有数据库锁
            map0.put("alarmsTime", alarmsTime);
        }else{
            map0.put("alarmsTime", alarmsTime);
        }
//        Object alarmsTime = CacheUtil.getFromCache("alarmsTime");
//        if (alarmsTime != null) {
//            int alarmsTime1 = (int) alarmsTime;
//
//            // 检查当前值是否大于 0
//            if (alarmsTime1 > 0) {
//                alarmsTime1--;  // 减一
//                CacheUtil.putInCache("alarmsTime", alarmsTime1); // 更新缓存
//                map0.put("alarmsTime", alarmsTime1); // 更新地图
//            }
//        }
        //把map转为json
        String json = JSON.toJSONString(map0);
        log.info("json推修改警报数消息:"+json);
        //System.out.println("json推警报数消息:"+json);
        //更新警报缓存
        CacheUtil.putInCache("alarmsTime", alarmsTime);
        webSocketServer.sendToAllClient(json);//推消息
    }

    //-----------------------------------------
    //优化后：
    @PostMapping("/torqueData")
    @CrossOrigin
    @Transactional(readOnly = true) // 查询操作设为只读事务，不影响数据查询
    public Result getTorqueData(@RequestBody QueryTorqueDataCondition queryCondition) {
        System.out.println("queryCondition是:"+queryCondition);
        log.info("大曲线请求线程 - ID: {}, 名称: {}",
                Thread.currentThread().getId(),
                Thread.currentThread().getName());

        // 1. 解析月份参数（保留原校验逻辑）
        String monthStr = queryCondition.getMonth();
        YearMonth yearMonth;
        if (monthStr == null || !monthStr.matches("\\d{4}-\\d{2}")) {
            return new Result(Code.SAVE_OK, "月份格式不正确（正确格式：yyyy-MM）");
        } else {
            try {
                yearMonth = YearMonth.parse(monthStr);
            } catch (DateTimeParseException e) {
                log.warn("月份解析失败: {}", monthStr);
                return new Result(Code.SAVE_OK, "月份格式不正确");
            }
        }

        // 2. 构建时间范围（与原逻辑完全一致）
        LocalDateTime startDate = yearMonth.atDay(1).atStartOfDay();
        LocalDateTime endDate = yearMonth.atEndOfMonth().atTime(23, 59, 59);
        Date start = Date.from(startDate.atZone(ZoneId.systemDefault()).toInstant());
        Date end = Date.from(endDate.atZone(ZoneId.systemDefault()).toInstant());

        // 3. 构建螺丝查询条件（保留原逻辑，仅优化冗余判断）
        LambdaQueryWrapper<Screw> queryWrapper = new LambdaQueryWrapper<>();
        // 3.1 车型条件
        String carType = queryCondition.getCarType();
        if (carType != null && !carType.isEmpty()) {
            LambdaQueryWrapper<Car> carQuery = new LambdaQueryWrapper<>();
            carQuery.eq(Car::getCarType, carType);
            List<Car> carList = carMapper.selectList(carQuery);
            List<Long> carIds = carList.stream().map(Car::getId).toList();
            if (!carIds.isEmpty()) {
                queryWrapper.in(Screw::getCarId, carIds);
            }
        }

        // 3.2 工位与螺丝类型条件（完全保留原逻辑，避免修改导致条件错误）
        String workingPosition = queryCondition.getWorkingPosition();
        if (workingPosition != null && !workingPosition.isEmpty()) {
            String screwTypeId = queryCondition.getScrewTypeId();
            if (screwTypeId != null && !screwTypeId.isEmpty()) {
                queryWrapper.eq(Screw::getScrewTypeId, screwTypeId);
            } else {
                switch (workingPosition) {
                    case "左前":
                        queryWrapper.in(Screw::getScrewTypeId, "1", "2", "3", "4");
                        break;
                    case "左后":
                        queryWrapper.in(Screw::getScrewTypeId, "5", "6", "7", "8");
                        break;
                    case "右前":
                        queryWrapper.in(Screw::getScrewTypeId, "9", "10", "11", "12");
                        break;
                    case "右后":
                        queryWrapper.in(Screw::getScrewTypeId, "13", "14", "15", "16");
                        break;
//                    case "发动机盖L":
//                        queryWrapper.in(Screw::getScrewTypeId, "17", "18");
//                    case "发动机盖R":
//                        queryWrapper.in(Screw::getScrewTypeId, "19", "20");
                    case "发动机盖":
                        queryWrapper.in(Screw::getScrewTypeId, "17", "18", "19", "20");
                        break;
                    // 保留原逻辑：不匹配时不添加条件（原代码无默认处理）
                }
            }
        }

        // 3.3 时间范围与排序（与原逻辑一致）
        queryWrapper.between(Screw::getCreateTime, start, end)
                .orderByAsc(Screw::getCreateTime);
        List<Screw> allScrewData = screwMapper.selectList(queryWrapper);
        log.debug("查询到螺丝数据总量: {}", allScrewData.size()); // 调试日志，确认数据是否查询到
        System.out.println("查询到螺丝数据总量: "+allScrewData.size());

        // 4. 按车辆频率采样（核心逻辑完全保留，仅修复空指针隐患）
        Map<String, List<Screw>> sampledDataMap = new HashMap<>();
        Map<String, List<Screw>> currentCarScrews = new HashMap<>();
        List<String> screwTypeList = new ArrayList<>();
        Long currentCarId = null; // 初始为null
        int carCount = 0;
        int sampleFrequency = frequencyProperties.getTorqueDataFrequency();
        log.debug("采样频率: {}", sampleFrequency);

        for (Screw screw : allScrewData) {
            Long carId = screw.getCarId();
            // 处理车辆切换：避免currentCarId为null时的空指针（原逻辑潜在问题）
            if (!Objects.equals(carId, currentCarId)) {
                // 达到采样频率时保存当前车辆数据
                if (carCount == sampleFrequency) {
                    // 遍历当前车辆的螺丝数据，添加到采样结果
                    for (Map.Entry<String, List<Screw>> entry : currentCarScrews.entrySet()) {
                        String stId = entry.getKey();
                        List<Screw> screws = entry.getValue();
                        String mapKey = "screwType" + stId;

                        // 记录螺丝类型（去重）
                        if (stId != null && !screwTypeList.contains(mapKey)) {
                            screwTypeList.add(mapKey);
                        }
                        // 合并到采样结果
                        sampledDataMap.computeIfAbsent(mapKey, k -> new ArrayList<>()).addAll(screws);
                        log.trace("采样添加螺丝类型: {}, 数量: {}", mapKey, screws.size());
                    }
                    carCount = 0; // 重置计数
                    log.debug("触发采样，重置计数器");
                }
                // 更新车辆信息
                currentCarId = carId;
                carCount++;
                currentCarScrews.clear();
            }
            // 按螺丝类型分组当前车辆数据
            String screwTypeId = String.valueOf(screw.getScrewTypeId());
            currentCarScrews.computeIfAbsent(screwTypeId, k -> new ArrayList<>()).add(screw);
        }
        log.debug("采样后数据映射大小: {}", sampledDataMap.size()); // 确认采样是否有数据

        // 5. 螺丝类型排序（与原逻辑一致）
        Collections.sort(screwTypeList, (o1, o2) -> {
            int num1 = Integer.parseInt(o1.replaceAll("\\D+", ""));
            int num2 = Integer.parseInt(o2.replaceAll("\\D+", ""));
            return Integer.compare(num1, num2);
        });
        log.debug("排序后螺丝类型: {}", screwTypeList);

        // 6. 转换为ScrewExt并去重（保留原逻辑的调用方式）
        List<ScrewExt> sampledData0 = new ArrayList<>();
        List<ScrewExt> sampledData02 = new ArrayList<>();
        List<ScrewExt> sampledData03 = new ArrayList<>();
        List<ScrewExt> sampledData04 = new ArrayList<>();

        System.out.println(screwTypeList.size() + "screwTypeList是" + screwTypeList);

        //优化后：
        // 2. 主处理逻辑（根据列表长度分发处理）
        if (screwTypeList.size() == 4) {
            // 长度为4时，按顺序对应四个列表
            assignData(screwTypeList.get(0), sampledData0, sampledDataMap);
            assignData(screwTypeList.get(1), sampledData02, sampledDataMap);
            assignData(screwTypeList.get(2), sampledData03, sampledDataMap);
            assignData(screwTypeList.get(3), sampledData04, sampledDataMap);
        } else if (screwTypeList.size() == 3) {
            handleSize3(screwTypeList, sampledData0, sampledData02, sampledData03, sampledData04, sampledDataMap);
        } else if (screwTypeList.size() == 2) {
            handleSize2(screwTypeList, sampledData0, sampledData02, sampledData03, sampledData04, sampledDataMap);
        } else if (screwTypeList.size() == 1) {
            handleSize1(screwTypeList, sampledData0, sampledData02, sampledData03, sampledData04, sampledDataMap);
        }

        //-------------------
        //优化前：
//        if(screwTypeList.size() == 4) {
//            // 提取前4种螺丝类型的数据（与原逻辑一致）
////            if (!screwTypeList.isEmpty()) {
//                sampledData0 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData0);
////            }
////            if (screwTypeList.size() > 1) {
//                sampledData02 = extracted(sampledDataMap.get(screwTypeList.get(1)), sampledData02);
////            }
////            if (screwTypeList.size() > 2) {
//                sampledData03 = extracted(sampledDataMap.get(screwTypeList.get(2)), sampledData03);
////            }
////            if (screwTypeList.size() > 3) {
//                sampledData04 = extracted(sampledDataMap.get(screwTypeList.get(3)), sampledData04);
////            }
//        }else if(screwTypeList.size() == 3) {
//            //123
//            if((screwTypeList.get(0).equals("screwType1")
//                    || screwTypeList.get(0).equals("screwType5")
//                    || screwTypeList.get(0).equals("screwType9")
//                    || screwTypeList.get(0).equals("screwType13"))
//            && (screwTypeList.get(1).equals("screwType2")
//                    || screwTypeList.get(1).equals("screwType6")
//                    || screwTypeList.get(1).equals("screwType10")
//                    || screwTypeList.get(1).equals("screwType14"))
//            && (screwTypeList.get(2).equals("screwType3")
//                    || screwTypeList.get(2).equals("screwType7")
//                    || screwTypeList.get(2).equals("screwType11")
//                    || screwTypeList.get(2).equals("screwType15"))) {
//                sampledData0 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData0);
//                sampledData02 = extracted(sampledDataMap.get(screwTypeList.get(1)), sampledData02);
//                sampledData03 = extracted(sampledDataMap.get(screwTypeList.get(2)), sampledData03);
//            }
//            //234
//            if((screwTypeList.get(0).equals("screwType2")
//                    || screwTypeList.get(0).equals("screwType6")
//                    || screwTypeList.get(0).equals("screwType10")
//                    || screwTypeList.get(0).equals("screwType14"))
//            && (screwTypeList.get(1).equals("screwType3")
//                    || screwTypeList.get(1).equals("screwType7")
//                    || screwTypeList.get(1).equals("screwType11")
//                    || screwTypeList.get(1).equals("screwType15"))
//            && (screwTypeList.get(2).equals("screwType4")
//                    || screwTypeList.get(2).equals("screwType8")
//                    || screwTypeList.get(2).equals("screwType12")
//                    || screwTypeList.get(2).equals("screwType16"))) {
//                sampledData02 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData02);
//                sampledData03 = extracted(sampledDataMap.get(screwTypeList.get(1)), sampledData03);
//                sampledData04 = extracted(sampledDataMap.get(screwTypeList.get(2)), sampledData04);
//            }
//            //134
//            if((screwTypeList.get(0).equals("screwType1")
//                    || screwTypeList.get(0).equals("screwType5")
//                    || screwTypeList.get(0).equals("screwType9")
//                    || screwTypeList.get(0).equals("screwType13"))
//            && (screwTypeList.get(1).equals("screwType3")
//                    || screwTypeList.get(1).equals("screwType7")
//                    || screwTypeList.get(1).equals("screwType11")
//                    || screwTypeList.get(1).equals("screwType15"))
//            && (screwTypeList.get(2).equals("screwType4")
//                    || screwTypeList.get(2).equals("screwType8")
//                    || screwTypeList.get(2).equals("screwType12")
//                    || screwTypeList.get(2).equals("screwType16"))) {
//                sampledData0 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData0);
//                sampledData03 = extracted(sampledDataMap.get(screwTypeList.get(1)), sampledData03);
//                sampledData04 = extracted(sampledDataMap.get(screwTypeList.get(2)), sampledData04);
//            }
//            //124
//            if((screwTypeList.get(0).equals("screwType1")
//                    || screwTypeList.get(0).equals("screwType5")
//                    || screwTypeList.get(0).equals("screwType9")
//                    || screwTypeList.get(0).equals("screwType13"))
//            && (screwTypeList.get(1).equals("screwType2")
//                    || screwTypeList.get(1).equals("screwType6")
//                    || screwTypeList.get(1).equals("screwType10")
//                    || screwTypeList.get(1).equals("screwType14"))
//            && (screwTypeList.get(2).equals("screwType4")
//                    || screwTypeList.get(2).equals("screwType8")
//                    || screwTypeList.get(2).equals("screwType12")
//                    || screwTypeList.get(2).equals("screwType16"))) {
//                sampledData0 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData0);
//                sampledData02 = extracted(sampledDataMap.get(screwTypeList.get(1)), sampledData02);
//                sampledData04 = extracted(sampledDataMap.get(screwTypeList.get(2)), sampledData04);
//            }
//        }else if(screwTypeList.size() == 2){
//            //12
//            if(screwTypeList.get(0).equals("screwType1")
//                    || screwTypeList.get(0).equals("screwType5")
//                    || screwTypeList.get(0).equals("screwType9")
//                    || screwTypeList.get(0).equals("screwType13")
//                    || screwTypeList.get(0).equals("screwType17")){
//                sampledData0 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData0);
//            }else if(screwTypeList.get(1).equals("screwType2")
//                    || screwTypeList.get(1).equals("screwType6")
//                    || screwTypeList.get(1).equals("screwType10")
//                    || screwTypeList.get(1).equals("screwType14")
//                    || screwTypeList.get(1).equals("screwType18")) {
//                sampledData02 = extracted(sampledDataMap.get(screwTypeList.get(1)), sampledData02);
//            }
//                //34
//            if(screwTypeList.get(0).equals("screwType3")
//                    || screwTypeList.get(0).equals("screwType7")
//                    || screwTypeList.get(0).equals("screwType11")
//                    || screwTypeList.get(0).equals("screwType15")
//                    || screwTypeList.get(0).equals("screwType19")){
//                sampledData03 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData03);
//            }else if(screwTypeList.get(1).equals("screwType4")
//                    || screwTypeList.get(1).equals("screwType8")
//                    || screwTypeList.get(1).equals("screwType12")
//                    || screwTypeList.get(1).equals("screwType16")
//                    || screwTypeList.get(1).equals("screwType20")) {
//                sampledData04 = extracted(sampledDataMap.get(screwTypeList.get(1)), sampledData04);
//            }
//                //23
//            if(screwTypeList.get(0).equals("screwType2")
//                    || screwTypeList.get(0).equals("screwType6")
//                    || screwTypeList.get(0).equals("screwType10")
//                    || screwTypeList.get(0).equals("screwType14")
//                    || screwTypeList.get(0).equals("screwType18")){
//                sampledData02 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData02);
//            }else if(screwTypeList.get(1).equals("screwType3")
//                    || screwTypeList.get(1).equals("screwType7")
//                    || screwTypeList.get(1).equals("screwType11")
//                    || screwTypeList.get(1).equals("screwType15")
//                    || screwTypeList.get(1).equals("screwType19")){
//                sampledData03 = extracted(sampledDataMap.get(screwTypeList.get(1)), sampledData03);
//            }
//            //13
//            if(screwTypeList.get(0).equals("screwType1")
//                    || screwTypeList.get(0).equals("screwType5")
//                    || screwTypeList.get(0).equals("screwType9")
//                    || screwTypeList.get(0).equals("screwType13")
//                    || screwTypeList.get(0).equals("screwType17")){
//                sampledData0 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData0);
//            }else if(screwTypeList.get(1).equals("screwType3")
//                    || screwTypeList.get(1).equals("screwType7")
//                    || screwTypeList.get(1).equals("screwType11")
//                    || screwTypeList.get(1).equals("screwType15")
//                    || screwTypeList.get(1).equals("screwType19")){
//                sampledData03 = extracted(sampledDataMap.get(screwTypeList.get(1)), sampledData03);
//            }
//            //24
//            if(screwTypeList.get(0).equals("screwType2")
//                    || screwTypeList.get(0).equals("screwType6")
//                    || screwTypeList.get(0).equals("screwType10")
//                    || screwTypeList.get(0).equals("screwType14")
//                    || screwTypeList.get(0).equals("screwType18")) {
//                sampledData02 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData02);
//            }else if(screwTypeList.get(1).equals("screwType4")
//                    || screwTypeList.get(1).equals("screwType8")
//                    || screwTypeList.get(1).equals("screwType12")
//                    || screwTypeList.get(1).equals("screwType16")
//                    || screwTypeList.get(1).equals("screwType20")) {
//                sampledData04 = extracted(sampledDataMap.get(screwTypeList.get(1)), sampledData04);
//            }
//            //14
//            if(screwTypeList.get(0).equals("screwType1")
//                    || screwTypeList.get(0).equals("screwType5")
//                    || screwTypeList.get(0).equals("screwType9")
//                    || screwTypeList.get(0).equals("screwType13")
//                    || screwTypeList.get(0).equals("screwType17")){
//                sampledData0 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData0);
//            }else if(screwTypeList.get(1).equals("screwType4")
//                    || screwTypeList.get(1).equals("screwType8")
//                    || screwTypeList.get(1).equals("screwType12")
//                    || screwTypeList.get(1).equals("screwType16")
//                    || screwTypeList.get(1).equals("screwType20")) {
//                sampledData04 = extracted(sampledDataMap.get(screwTypeList.get(1)), sampledData04);
//            }
//
//        } else if(screwTypeList.size() == 1) {
//            if(screwTypeList.contains("screwType1") || screwTypeList.contains("screwType5")
//                    || screwTypeList.contains("screwType9") || screwTypeList.contains("screwType13")
//                    || screwTypeList.contains("screwType17")){
//                sampledData0 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData0);
//            }else if(screwTypeList.contains("screwType2") || screwTypeList.contains("screwType6")
//                    || screwTypeList.contains("screwType10") || screwTypeList.contains("screwType14")
//                    || screwTypeList.contains("screwType18")){
//                sampledData02 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData02);
//            }else if(screwTypeList.contains("screwType3") || screwTypeList.contains("screwType7")
//                    || screwTypeList.contains("screwType11") || screwTypeList.contains("screwType15")
//                    || screwTypeList.contains("screwType19")){
//                sampledData03 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData03);
//            }else if(screwTypeList.contains("screwType4") || screwTypeList.contains("screwType8")
//                    || screwTypeList.contains("screwType12") || screwTypeList.contains("screwType16")
//                    || screwTypeList.contains("screwType20")){
//                sampledData04 = extracted(sampledDataMap.get(screwTypeList.get(0)), sampledData04);
//            }
//        }

        // 去重处理（与原逻辑一致）
        sampledData0 = removeDuplicates(sampledData0);
        sampledData02 = removeDuplicates(sampledData02);
        sampledData03 = removeDuplicates(sampledData03);
        sampledData04 = removeDuplicates(sampledData04);

        log.debug("去重后各列表大小: {}, {}, {}, {}",
                sampledData0.size(), sampledData02.size(),
                sampledData03.size(), sampledData04.size());

        // 7. 查询扭矩标准（与原逻辑完全一致）
        TorqueStandards torqueStandards = null;
        if (workingPosition != null && !workingPosition.isEmpty()) {
            LambdaQueryWrapper<TorqueStandards> tsQuery = new LambdaQueryWrapper<>();
            // 工位匹配
            if (Arrays.asList("左前", "左后", "右前", "右后").contains(workingPosition)) {
                tsQuery.eq(TorqueStandards::getWorkingPositionId, MessageConstant.workingPosition1);
            } else if ("发动机盖".equals(workingPosition)) {
                tsQuery.eq(TorqueStandards::getWorkingPositionId, MessageConstant.workingPosition2);
            } else {
                return new Result(Code.SELECT_ERR, "未知搜索部位");
            }
            // 车型条件
            if (carType != null && !carType.isEmpty()) {
                tsQuery.eq(TorqueStandards::getCarType, carType);
                int tsCount = torqueStandardsMapper.selectCount(tsQuery);
                if (tsCount == 1) {
                    torqueStandards = torqueStandardsMapper.selectOne(tsQuery);
                }
            }
        }

        // 8. 封装返回结果（与原结构完全一致）
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("sampledData0", sampledData0);
        resultMap.put("sampledData02", sampledData02);
        resultMap.put("sampledData03", sampledData03);
        resultMap.put("sampledData04", sampledData04);
        resultMap.put("torqueStandards", torqueStandards);

        log.info("曲线图表数据返回，包含字段: {}", resultMap.keySet());
        return new Result(Code.SELECT_OK, resultMap);
    }

    /**
     * 处理长度为3的螺丝类型列表
     */
    private void handleSize3(List<String> typeList,
                             List<ScrewExt> data0, List<ScrewExt> data02,
                             List<ScrewExt> data03, List<ScrewExt> data04,
                             Map<String, List<Screw>> dataMap) {
        String t0 = typeList.get(0);
        String t1 = typeList.get(1);
        String t2 = typeList.get(2);

        // 123组合
        if (isInGroup(t0, "0") && isInGroup(t1, "02") && isInGroup(t2, "03")) {
            assignData(t0, data0, dataMap);
            assignData(t1, data02, dataMap);
            assignData(t2, data03, dataMap);
        }
        // 234组合
        else if (isInGroup(t0, "02") && isInGroup(t1, "03") && isInGroup(t2, "04")) {
            assignData(t0, data02, dataMap);
            assignData(t1, data03, dataMap);
            assignData(t2, data04, dataMap);
        }
        // 134组合
        else if (isInGroup(t0, "0") && isInGroup(t1, "03") && isInGroup(t2, "04")) {
            assignData(t0, data0, dataMap);
            assignData(t1, data03, dataMap);
            assignData(t2, data04, dataMap);
        }
        // 124组合
        else if (isInGroup(t0, "0") && isInGroup(t1, "02") && isInGroup(t2, "04")) {
            assignData(t0, data0, dataMap);
            assignData(t1, data02, dataMap);
            assignData(t2, data04, dataMap);
        }
    }

    /**
     * 处理长度为2的螺丝类型列表
     */
    private void handleSize2(List<String> typeList,
                             List<ScrewExt> data0, List<ScrewExt> data02,
                             List<ScrewExt> data03, List<ScrewExt> data04,
                             Map<String, List<Screw>> dataMap) {
        String t0 = typeList.get(0);
        String t1 = typeList.get(1);

        // 检查每个类型属于哪个组，并赋值
        assignByGroup(t0, data0, data02, data03, data04, dataMap);
        assignByGroup(t1, data0, data02, data03, data04, dataMap);
    }

    /**
     * 处理长度为1的螺丝类型列表
     */
    private void handleSize1(List<String> typeList,
                             List<ScrewExt> data0, List<ScrewExt> data02,
                             List<ScrewExt> data03, List<ScrewExt> data04,
                             Map<String, List<Screw>> dataMap) {
        String type = typeList.get(0);
        assignByGroup(type, data0, data02, data03, data04, dataMap);
    }

    /**
     * 检查螺丝类型属于哪个组
     */
    private boolean isInGroup(String screwType, String groupKey) {
        return TYPE_GROUP_MAP.getOrDefault(groupKey, Collections.emptyList()).contains(screwType);
    }

    /**
     * 根据类型所属组，自动分配到对应的目标列表
     */
    private void assignByGroup(String screwType,
                               List<ScrewExt> data0, List<ScrewExt> data02,
                               List<ScrewExt> data03, List<ScrewExt> data04,
                               Map<String, List<Screw>> dataMap) {
        if (isInGroup(screwType, "0")) {
            assignData(screwType, data0, dataMap);
        } else if (isInGroup(screwType, "02")) {
            assignData(screwType, data02, dataMap);
        } else if (isInGroup(screwType, "03")) {
            assignData(screwType, data03, dataMap);
        } else if (isInGroup(screwType, "04")) {
            assignData(screwType, data04, dataMap);
        }
    }

    /**
     * 核心通用方法：从dataMap提取数据并赋值给目标列表
     */
    private void assignData(String screwType, List<ScrewExt> targetList, Map<String, List<Screw>> dataMap) {
        if (screwType == null || dataMap == null) {
            return;
        }
        List<Screw> screws = dataMap.get(screwType);
        if (screws != null) {
            targetList.addAll(extracted(screws, new ArrayList<>())); // 复用原extracted方法
        }
    }

    // 保留原逻辑的去重方法（与原代码行为一致）
    private List<ScrewExt> removeDuplicates(List<ScrewExt> list) {
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        Set<ScrewExt> set = new LinkedHashSet<>(list); // 保留顺序去重
        return new ArrayList<>(set);
    }

    // 保留原代码中的extracted方法调用（假设该方法实现Screw到ScrewExt的转换）
// 注意：需确保该方法在原代码中存在且正确实现转换
//    private List<ScrewExt> extracted(List<Screw> screws, List<ScrewExt> extList) {
//        if (screws == null) {
//            return extList;
//        }
//        // 此处逻辑与原代码中的extracted保持一致（用户未提供实现，暂按转换逻辑示例）
//        for (Screw s : screws) {
//            ScrewExt ext = new ScrewExt();
//            // 复制属性（根据实际业务调整）
//            ext.setId(s.getId());
//            ext.setTorque(s.getTorque());
//            ext.setCreateTime(s.getCreateTime());
//            ext.setScrewTypeId(s.getScrewTypeId());
//            ext.setCarId(s.getCarId());
//            extList.add(ext);
//        }
//        return extList;
//    }

    //------------------------------------
    //优化前：
    //大曲线图表
//    @PostMapping("/torqueData")
//    @CrossOrigin
//    @Transactional
//    public Result getTorqueData(@RequestBody QueryTorqueDataCondition queryTorqueDataCondition) {
//        log.info("大曲线的线程id:{}", Thread.currentThread().getId()+"名"+Thread.currentThread().getName());
//
//        //System.out.println("大曲线参数："+queryTorqueDataCondition);
//        // 解析请求参数，构建本月的开始时间
////        LocalDateTime startDate = LocalDateTime.parse(queryTorqueDataCondition.getMonth() + "-01T00:00:00");
////        LocalDateTime endDate = startDate.plusMonths(1).minusSeconds(1); // 本月最后一秒
//        String monthStr = queryTorqueDataCondition.getMonth();
//        YearMonth ym;
//        if (monthStr == null || !monthStr.matches("\\d{4}-\\d{2}")) {
//            // 使用当前月份作为默认值
//            //ym = YearMonth.now();
//            return new Result(Code.SAVE_OK, "月份格式不正确");
//        } else {
//            ym = YearMonth.parse(monthStr);
//        }
////        YearMonth ym = YearMonth.parse(queryTorqueDataCondition.getMonth());
//        LocalDateTime startDate = ym.atDay(1).atStartOfDay();
////        //System.out.println("startDate是"+startDate);
//        LocalDateTime endDate = ym.atEndOfMonth().atTime(23,59,59);
////        //System.out.println("endDate是"+endDate);
//        // 获取当月所有螺丝数据
//        LambdaQueryWrapper<Screw> queryWrapper = new LambdaQueryWrapper<>();
////        根据工位搜索
////        queryWrapper.eq(queryTorqueDataCondition.getWorkingPositionId()!=null &&
////                        !queryTorqueDataCondition.getWorkingPositionId().isEmpty(),Screw::getWorkingPositionId,
////                queryTorqueDataCondition.getWorkingPositionId());
//        //根据车型搜索螺丝
//        if(queryTorqueDataCondition.getCarType()!=null &&
//                !queryTorqueDataCondition.getCarType().isEmpty()){
//            //根据车型获取相关车ID
//            LambdaQueryWrapper<Car> queryCarWrapper = new LambdaQueryWrapper<>();
//            queryCarWrapper.eq(Car::getCarType, queryTorqueDataCondition.getCarType());
//            List<Car> carList = carMapper.selectList(queryCarWrapper);
//            List<Long> carIds = carList.stream().map(Car::getId).toList();
//            if(!carIds.isEmpty()) {
//                queryWrapper.in(Screw::getCarId,
//                        carIds);
//            }
//        }
//
//        //根据工位,"左前""左后""右前""右后""车盖"
//        if(queryTorqueDataCondition.getWorkingPosition()!=null &&
//                !queryTorqueDataCondition.getWorkingPosition().isEmpty()){
//            if (queryTorqueDataCondition.getScrewTypeId() != null &&
//                    !queryTorqueDataCondition.getScrewTypeId().isEmpty()) {
//                queryWrapper.eq(Screw::getScrewTypeId, queryTorqueDataCondition.getScrewTypeId());
//            } else {
//                if (queryTorqueDataCondition.getWorkingPosition().equals("左前")) {
//                    queryWrapper.in(Screw::getScrewTypeId, "1", "2", "3", "4");
////                    queryWrapper.eq(Screw::getScrewTypeId, "1")
////                            .or(i -> i.and(j -> j.eq(Screw::getScrewTypeId, "2")
////                                    .or(k -> k.eq(Screw::getScrewTypeId, "3")
////                                            .or().eq(Screw::getScrewTypeId, "4"))));
////                    queryWrapper.eq(Screw::getScrewTypeId, "1")
////                            .or(i -> i.eq(Screw::getScrewTypeId, "2")
////                                    .or().eq(Screw::getScrewTypeId, "3")
////                                    .or().eq(Screw::getScrewTypeId, "4"));
//
//                } else if (queryTorqueDataCondition.getWorkingPosition().equals("左后")) {
//                    queryWrapper.in(Screw::getScrewTypeId, "5", "6", "7", "8");
////                    queryWrapper.eq(Screw::getScrewTypeId, "5")
////                            .or(i -> i.and(j -> j.eq(Screw::getScrewTypeId, "6")
////                                    .or().eq(Screw::getScrewTypeId, "7")
////                                    .or().eq(Screw::getScrewTypeId, "8")));
////                    queryWrapper.eq(Screw::getScrewTypeId, "5")
////                            .or(i -> i.eq(Screw::getScrewTypeId, "6")
////                                    .or().eq(Screw::getScrewTypeId, "7")
////                                    .or().eq(Screw::getScrewTypeId, "8"));
//
//                } else if (queryTorqueDataCondition.getWorkingPosition().equals("右前")) {
//                    queryWrapper.in(Screw::getScrewTypeId, "9", "10", "11", "12");
////                    queryWrapper.eq(Screw::getScrewTypeId, "9")
////                            .or(i -> i.and(j -> j.eq(Screw::getScrewTypeId, "10")
////                                    .or(k -> k.eq(Screw::getScrewTypeId, "11")
////                                            .or().eq(Screw::getScrewTypeId, "12"))));
////                    queryWrapper.eq(Screw::getScrewTypeId, "9")
////                            .or(i -> i.eq(Screw::getScrewTypeId, "10")
////                                    .or().eq(Screw::getScrewTypeId, "11")
////                                    .or().eq(Screw::getScrewTypeId, "12"));
//
//                } else if (queryTorqueDataCondition.getWorkingPosition().equals("右后")) {
//                    queryWrapper.in(Screw::getScrewTypeId, "13", "14", "15", "16");
////                    queryWrapper.eq(Screw::getScrewTypeId, "13")
////                            .or(i -> i.and(j -> j.eq(Screw::getScrewTypeId, "14")
////                                    .or(k -> k.eq(Screw::getScrewTypeId, "15")
////                                            .or().eq(Screw::getScrewTypeId, "16"))));
////                    queryWrapper.eq(Screw::getScrewTypeId, "13")
////                            .or(i -> i.eq(Screw::getScrewTypeId, "14")
////                                    .or().eq(Screw::getScrewTypeId, "15")
////                                    .or().eq(Screw::getScrewTypeId, "16"));
//
//                } else if (queryTorqueDataCondition.getWorkingPosition().equals("发动机盖")) {
//                    queryWrapper.in(Screw::getScrewTypeId, "17", "18", "19", "20");
////                    queryWrapper.eq(Screw::getScrewTypeId, "17")
////                            .or(i -> i.and(j -> j.eq(Screw::getScrewTypeId, "18")
////                                    .or(k -> k.eq(Screw::getScrewTypeId, "19")
////                                            .or().eq(Screw::getScrewTypeId, "20"))));
////                    queryWrapper.eq(Screw::getScrewTypeId, "17")
////                            .or(i -> i.eq(Screw::getScrewTypeId, "18")
////                                    .or().eq(Screw::getScrewTypeId, "19")
////                                    .or().eq(Screw::getScrewTypeId, "20"));
//
//                }
//            }
//        }
////        queryWrapper.eq(queryTorqueDataCondition.getWorkingPosition()!=null &&
////                        !queryTorqueDataCondition.getWorkingPosition().isEmpty(),
////                    Screw::getWorkingPositionId,
////                queryTorqueDataCondition.getWorkingPosition());
//
////        queryWrapper.eq(queryTorqueDataCondition.getScrewTypeId()!=null &&
////                        !queryTorqueDataCondition.getScrewTypeId().isEmpty(),
////                        Screw::getScrewTypeId,
////                queryTorqueDataCondition.getScrewTypeId());
//
//        // 根据时间范围搜索
////        //System.out.println("时间范围搜索");
//        queryWrapper.between(Screw::getCreateTime, Date.from(startDate.atZone(ZoneId.systemDefault()).toInstant()),
//                Date.from(endDate.atZone(ZoneId.systemDefault()).toInstant()));
//        //排序
//        queryWrapper.orderByAsc(Screw::getCreateTime);
//        List<Screw> allScrewData = screwMapper.selectList(queryWrapper);
//
////        log.info("allScrewData是"+allScrewData);
//
//        // 用于跟踪当前车的ID
//        Long currentCarId = null;
//        // 用于计数
//        int carCount = 0;
//
//////每30辆车采样一次
////
////        for (Screw screw : allScrewData) {
////            // 检查是否到了新的车
////            if (!screw.getCarId().equals(currentCarId)) {
////                currentCarId = screw.getCarId();
////                carCount++; // 新的车，计数器增加
////                // 每隔30辆车取一颗螺丝
////                if (carCount == frequencyProperties.getTorqueDataFrequency()) {
////                    log.info("carCount是"+carCount);
////                    sampledData.add(screw);
////                    carCount = 0; // 重置计数器
////                }
////            }
////        }
//
//// 假设这些列表已经被初始化
//
//        Map<String, List<Screw>> sampledDataMap = new HashMap<>();
//        // 当前车辆的螺丝数据Map
//        Map<String, List<Screw>> currentCarScrews = new HashMap<>();
//        List<String> screwTypeList = new ArrayList<>();
//        // 使用Set代替List
////        Set<String> screwTypeSet = new HashSet<>();
////        Set<String> screwTypeSet = new LinkedHashSet<>();
//        for (Screw screw : allScrewData) {
//            // 检查是否到了新的车
//            if (!screw.getCarId().equals(currentCarId)) {
//                // 如果是新车，检查是否需要采样
////                log.info("carCount是"+carCount);
////                log.info("frequencyProperties.getTorqueDataFrequency()是"+frequencyProperties.getTorqueDataFrequency());
//                if (carCount == frequencyProperties.getTorqueDataFrequency()) {
////                    log.info("carCount是"+carCount);
////                    log.info("frequencyProperties.getTorqueDataFrequency()是"+frequencyProperties.getTorqueDataFrequency());
//                    // 将当前车辆的所有螺丝按类型分类并添加到相应的采样数据列表中
////                    int screwTypeId = 1;
//                    for (Map.Entry<String, List<Screw>> entry : currentCarScrews.entrySet()) {
//                        String screwTypeId = entry.getKey();//String
//                        List<Screw> screws = entry.getValue();//List<Screw>
//                        log.info("screws是"+screws);
//                        // 确保sampledDataMap中有对应的列表
////                        sampledDataMap.computeIfAbsent(screwTypeId, k -> new ArrayList<>()).addAll(screws);
////                        sampledDataMap.put("screwType"+screwTypeId,screws);
//                        // 将screws列表合并到sampledDataMap中对应的列表
//                        log.info("当前是："+"screwType" + screwTypeId);
////                        //System.out.println("当前是："+"screwType" + screwTypeId);
//                        if (screwTypeId != null) {
//                            if (!screwTypeList.contains("screwType"+screwTypeId)) {
////                            screwTypeList.add("screwType" + screwTypeId);
//                                screwTypeList.add("screwType" + screwTypeId);
//                            }
//                        }
//                        sampledDataMap.computeIfAbsent("screwType" + screwTypeId,
//                                k -> new ArrayList<>()).addAll(screws);
//                        //sampledDataMap.computeIfAbsent方法用于确保Map中有一个键对应的列表，如果不存在则创建一个新列表，然后将当前车辆的螺丝数据添加到这个列表中。
////                        screwTypeId ++;
//                    }
//                    // 重置计数器
//
//                    carCount = 0;
//                    log.info("重置计数器"+carCount);
//                }
//                // 更新当前车辆ID
//                currentCarId = screw.getCarId();
//                // 新的车，计数器增加
//                carCount++;
//                // 清空当前车辆的螺丝数据
//                currentCarScrews.clear();
//            }
//            // 将螺丝添加到当前车辆的螺丝数据中
//            currentCarScrews.computeIfAbsent(String.valueOf(screw.getScrewTypeId()),
//                    k -> new ArrayList<>()).add(screw);
//        }
//
//        log.info("sampledDataMap是"+sampledDataMap);
//
//        // 循环结束后，检查最后一辆车是否需要采样
////        if (carCount == frequencyProperties.getTorqueDataFrequency()) {
////            for (Map.Entry<String, List<Screw>> entry : currentCarScrews.entrySet()) {
////                String screwTypeId = entry.getKey();
////                List<Screw> screws = entry.getValue();
////                sampledDataMap.computeIfAbsent(screwTypeId, k -> new ArrayList<>()).addAll(screws);
////            }
////        }
//
//        log.info("sampledDataMapLast是"+sampledDataMap);
//
////        log.info("sampledData是"+sampledData);
//        // 用于存储已经处理过的螺丝ID，避免重复
////        Set<Long> addedScrewIds = new HashSet<>();
//
//        // 生成从初始时间开始的每30分钟的时间点
////        LocalDateTime currentTime = startDate;
////        while (currentTime.isBefore(endDate)) {
//////            log.info("??");
////            int nearestIdx = binarySearchNearest(allScrewData, currentTime);
//////            log.info("nearestIdx是:"+nearestIdx);
////            if (nearestIdx != -1) {
////                Screw nearestScrew = allScrewData.get(nearestIdx);
////                if (addedScrewIds.add(nearestScrew.getId())) {
////                    log.info("最近的螺丝是："+nearestScrew);
////                    sampledData.add(nearestScrew);
////                }
////            }
////            currentTime = currentTime.plusMinutes(frequencyProperties.getTorqueDataFrequency());
////        }
//
//
//
//        TorqueStandards torqueStandards = null;
//        //上下限预警
//        LambdaQueryWrapper<TorqueStandards> torqueStandardsLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        if(queryTorqueDataCondition.getWorkingPosition() != null &&
//                !queryTorqueDataCondition.getWorkingPosition().isEmpty()){
//            if(queryTorqueDataCondition.getWorkingPosition().equals("左前") ||
//                    queryTorqueDataCondition.getWorkingPosition().equals("左后") ||
//                    queryTorqueDataCondition.getWorkingPosition().equals("右后") ||
//                    queryTorqueDataCondition.getWorkingPosition().equals("右前")){
//                torqueStandardsLambdaQueryWrapper.eq(TorqueStandards::getWorkingPositionId,
//                        MessageConstant.workingPosition1);
//            } else if(queryTorqueDataCondition.getWorkingPosition().equals("发动机盖")) {
//                torqueStandardsLambdaQueryWrapper.eq(TorqueStandards::getWorkingPositionId,
//                        MessageConstant.workingPosition2);
//            } else {
//                return new Result(Code.SELECT_ERR, "未知搜索部位");
//            }
//            if(!queryTorqueDataCondition.getCarType().isEmpty()){//没有选车型，不传扭力标准值
//                torqueStandardsLambdaQueryWrapper.eq(TorqueStandards::getCarType,
//                        queryTorqueDataCondition.getCarType());
//                Integer count = torqueStandardsMapper.selectCount(torqueStandardsLambdaQueryWrapper);
//                if (count == 1){
//                    torqueStandards = torqueStandardsMapper.selectOne(torqueStandardsLambdaQueryWrapper);
//                }
//            }
//        }
//
//        List<ScrewExt> sampledData0 = new ArrayList<>();
//        List<ScrewExt> sampledData02 = new ArrayList<>();
//        List<ScrewExt> sampledData03 = new ArrayList<>();
//        List<ScrewExt> sampledData04 = new ArrayList<>();
//
////        List<ScrewExt> declineScrews = new ArrayList<>(); // 先保存连续下降的螺丝
//
//        // 采样数据列表
//        List<Screw> sampledData = null;
//        List<Screw> sampledData2 = null;
//        List<Screw> sampledData3 = null;
//        List<Screw> sampledData4 = null;
//
////        Screw prevScrew = null;
////        int countDecline = 1; // 连续下降计数，从1开始算当前螺丝
//        log.info("sampledData循环之前"+sampledData);
//
//        //System.out.println("screwTypeList是："+screwTypeList);//[screwType19, screwType17, screwType18, screwType20]
//
//        // 使用自定义排序器根据数字部分排序
//        Collections.sort(screwTypeList, new Comparator<String>() {
//            public int compare(String o1, String o2) {
//                // 提取数字部分并转换为整数
//                int num1 = Integer.parseInt(o1.replaceAll("\\D+", ""));
//                int num2 = Integer.parseInt(o2.replaceAll("\\D+", ""));
//                return Integer.compare(num1, num2);
//            }
//        });
//
//        //System.out.println("screwTypeList排序后是："+screwTypeList);//[screwType17, screwType18, screwType19, screwType20]
//
//        if (!screwTypeList.isEmpty()) {
//            sampledData = sampledDataMap.get(screwTypeList.get(0));
//        }
////        sampledData = sampledDataMap.get("screwType"+1);
//        log.info("sampledData1是"+sampledData);
//        sampledData0 = extracted(sampledData, sampledData0);
//
//        if (!screwTypeList.isEmpty() && screwTypeList.size() > 1) {
//            sampledData2 = sampledDataMap.get(screwTypeList.get(1));
//        }
////        sampledData2 = sampledDataMap.get("screwType"+2);
//        log.info("sampledData2是"+sampledData2);
//        sampledData02 = extracted(sampledData2, sampledData02);
//
//        if (!screwTypeList.isEmpty() && screwTypeList.size() > 2) {
//            sampledData3 = sampledDataMap.get(screwTypeList.get(2));
//        }
////        sampledData3 = sampledDataMap.get("screwType"+3);
//        log.info("sampledData3是"+sampledData3);
//        sampledData03 = extracted(sampledData3, sampledData03);
//
//        if (!screwTypeList.isEmpty() && screwTypeList.size() > 3) {
//            sampledData4 = sampledDataMap.get(screwTypeList.get(3));
//        }
////        sampledData4 = sampledDataMap.get("screwType"+4);
//        log.info("sampledData4是"+sampledData4);
//        sampledData04 = extracted(sampledData4, sampledData04);
//
//
//
//        log.info("sampledData0是:"+sampledData0);
//        log.info("sampledData02是:"+sampledData02);
//        log.info("sampledData03是:"+sampledData03);
//        log.info("sampledData04是:"+sampledData04);
//        Set<ScrewExt> set = null;
//        if(sampledData0 != null){
//            set = new LinkedHashSet<>(sampledData0);
//            sampledData0.clear();
//            sampledData0.addAll(set);
//        }
//        Set<ScrewExt> set2 = null;
//        if(sampledData02 != null) {
//            set2 = new LinkedHashSet<>(sampledData02);
//            sampledData02.clear();
//            sampledData02.addAll(set2);
//        }
//        Set<ScrewExt> set3 = null;
//        if(sampledData03 != null){
//            set3 = new LinkedHashSet<>(sampledData03);
//            sampledData03.clear();
//            sampledData03.addAll(set3);
//        }
//        Set<ScrewExt> set4 = null;
//        if(sampledData04 != null) {
//            set4 = new LinkedHashSet<>(sampledData04);
//            sampledData04.clear();
//            sampledData04.addAll(set4);
//        }
//
//
//        log.info("sampledData0是:"+sampledData0);
//        log.info("sampledData02是:"+sampledData02);
//        log.info("sampledData03是:"+sampledData03);
//        log.info("sampledData04是:"+sampledData04);
//
//
//        Map map = new HashMap();
//        map.put("sampledData0",sampledData0);
//        map.put("sampledData02",sampledData02);
//        map.put("sampledData03",sampledData03);
//        map.put("sampledData04",sampledData04);
//        map.put("torqueStandards",torqueStandards);
//
//
//        // 返回采样后的数据
//        log.info("曲线图表数据：{}", map);
//        return new Result(Code.SELECT_OK, map);
//    }

    //判断连续下降
    private List<ScrewExt> extracted(List<Screw> sampledData,
                           List<ScrewExt> sampledData0) {
        List<ScrewExt> declineScrews = new ArrayList<>(); // 先保存连续下降的螺丝
        Screw prevScrew = null;
        int countDecline = 1; // 连续下降计数，从1开始算当前螺丝
        if(sampledData == null){
            return null;
        }
        for (Screw screw : sampledData) {
            ScrewExt screwExt = new ScrewExt();
            //复制属性
            BeanUtils.copyProperties(screw,screwExt);

            List<String> alarm = new ArrayList<>();
            CarStatus carStatus = carStatusMapper.selectOne(new LambdaQueryWrapper<CarStatus>().eq(CarStatus::getScrewId, screw.getId()));
            if(carStatus != null){
//             if(carStatus.getAlarmStatus().equals(CarStatus.AlarmStatus.alertUpperLimit)){
                 alarm.add(String.valueOf(carStatus.getAlarmStatus()));
                 alarm = alarm.stream().distinct().collect(Collectors.toList());
                 screwExt.setAlarm(alarm);
//             }
            }

            // 连续下降判断
            if (prevScrew != null && screw.getTorque() < prevScrew.getTorque()) {
                declineScrews.add(screwExt);
                // 当连续下降数量达到3个及以上，给所有这3个以上的螺丝标记告警
                if (countDecline > 2) {//2
                    int i = 1;
                    log.info("连续下降的螺丝有："+ declineScrews);
                    for (ScrewExt screwext : declineScrews){
                        String newFormattedCreateTime = convertLocalDateTimeToString(screwext.getCreateTime());
//            log.info("处理后时间数据：{}", newFormattedCreateTime);
                        screwext.setCreateTimeString(newFormattedCreateTime);

                        //前面存储的原本已经有了alarm的screwExt
                        List<String> alarm0 = screwext.getAlarm();

                        if(alarm0 != null){
                            //储存的第一颗和最后一颗螺丝不报连续下降
                            if(i != declineScrews.size() && i != 1){
                                alarm0.add(String.valueOf(CarStatus.AlarmStatus.continuingDecline));
                            }
                            i++;
                            alarm0 = alarm0.stream().distinct().collect(Collectors.toList());
                        }else {
                            alarm0 = new ArrayList<>();
                            if(i != declineScrews.size() && i != 1){
                                alarm0.add(String.valueOf(CarStatus.AlarmStatus.continuingDecline));
                            }
                            i++;
                            alarm0 = alarm0.stream().distinct().collect(Collectors.toList());
                        }

                        screwext.setAlarm(alarm0);
                        sampledData0.add(screwext);
                    }
                    //处理完之后清理//循环内不能盲目清空 declineScrews，
                    // 而应在循环结束后把未处理（未加入 sampledData0）的 declineScrews 数据补充进去。
//                    declineScrews.clear();
                    // 循环结束后，处理残留的 declineScrews
                    int a = 1;
                    log.info("处理残留的declineScrews1是"+ declineScrews);
                    for (ScrewExt screwext : declineScrews) {
                        //确保只加一次
                        if (a == 1 && a != declineScrews.size()) {
                            String newFormattedCreateTime = convertLocalDateTimeToString(screwext.getCreateTime());
                            screwext.setCreateTimeString(newFormattedCreateTime);
                            sampledData0.add(screwext);
                            a = 0;
                        }
                    }
//                    for (ScrewExt ds : declineScrews) {
//                        if (a == 1 && a != declineScrews.size()) {
//                            List<String> al = ds.getAlarm() != null ? ds.getAlarm() : new ArrayList<>();
//                            al.add(String.valueOf(CarStatus.AlarmStatus.continuingDecline));
//                            ds.setAlarm(al.stream().distinct().collect(Collectors.toList()));
//                        }
//                        ds.setCreateTimeString(convertLocalDateTimeToString(ds.getCreateTime()));
//                        a = 0;
//                    }
//                    sampledData0.addAll(declineScrews);
                    declineScrews.clear();
//                    countDecline = 0; // 可选，重置计数
                }
                countDecline++;
            } else {
                // 断开连续下降，清空缓存，重置计数器并加入当前螺丝
                countDecline = 1;
                log.info("处理残留的declineScrews2是"+ declineScrews);
                if (!declineScrews.isEmpty()) {
                    for (ScrewExt screwext : declineScrews) {
                        String newFormattedCreateTime = convertLocalDateTimeToString(screwext.getCreateTime());
                        screwext.setCreateTimeString(newFormattedCreateTime);
                        sampledData0.add(screwext);
                    }
                    declineScrews.clear();
                    declineScrews.add(screwExt);
                }


                String newFormattedCreateTime = convertLocalDateTimeToString(screw.getCreateTime());
//            log.info("处理后时间数据：{}", newFormattedCreateTime);
                screwExt.setCreateTimeString(newFormattedCreateTime);
                alarm = alarm.stream().distinct().collect(Collectors.toList());
                screwExt.setAlarm(alarm);
                sampledData0.add(screwExt);
            }
//            log.info("sampledData01是:"+sampledData0);
//            Set<ScrewExt> set = new LinkedHashSet<>(sampledData0);
//            sampledData0.clear();
//            log.info("sampledData02是:"+sampledData0);
//            sampledData0.addAll(set);
//            log.info("sampledData03是:"+sampledData0);

//            List<ScrewExt> distinctList = sampledData0.stream()
//                    .filter(distinctByKey(ScrewExt::getId))  // 或者换成你唯一标识的方法
//                    .toList();
//
//            sampledData0.clear();
//            sampledData0.addAll(distinctList);
            //保存当前螺丝的信息，用于跟下一颗判断是否下降
            prevScrew = screw;
        }
// for循环结束后

        //一定要再加一段**处理残余declineScrews**的代码（循环外），
        // 否则最后一批没有断开的连续下降数据不会被加入：
        if (!declineScrews.isEmpty()) {
            for (ScrewExt screwext : declineScrews) {
                String newFormattedCreateTime = convertLocalDateTimeToString(screwext.getCreateTime());
                screwext.setCreateTimeString(newFormattedCreateTime);
                sampledData0.add(screwext);
            }
            declineScrews.clear();
        }
        return sampledData0;
    }

    //每个时间点，用二分查找找到 createTime <= currentTime 的最大数据:
//    private int binarySearchNearest(List<Screw> sortedScrews, LocalDateTime currentTime) {
//        int left = 0, right = sortedScrews.size() - 1;
//        int result = -1;
//        while (left <= right) {
//            int mid = (left + right) / 2;
//            LocalDateTime midTime = convertDateToLocalDateTime(sortedScrews.get(mid).getCreateTime());
//            if (!midTime.isAfter(currentTime)) {
//                result = mid;        // midTime <= currentTime, 记录位置，向右继续查找更大满足条件的索引
//                left = mid + 1;
//            } else {
//                right = mid - 1;
//            }
//        }
//        return result;
//    }

    //    public static <T> Predicate<T> distinctByKey(Function<? super T, Object> keyExtractor) {
//        Set<Object> seen = ConcurrentHashMap.newKeySet();
//        return t -> seen.add(keyExtractor.apply(t));
//    }
    private static String convertLocalDateTimeToString(Date Time) {
        LocalDateTime localDateTime = Time.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        String formattedTime = String.format("%04d:%02d:%02d:%02d:%02d",
                localDateTime.getYear(),
                localDateTime.getMonthValue(),
                localDateTime.getDayOfMonth(),
                localDateTime.getHour(),
                localDateTime.getMinute());
//        log.info("formattedTime是"+formattedTime);
        // 使用 replace() 方法替换第一个 ':' 为 '-'
        // 使用正则表达式替换前两个 ':' 为 '-'
        // 拆分字符串
        String[] parts = formattedTime.split(":");
        // 重新组装字符串
        String newFormattedTime = String.join("-", parts[0], parts[1]) + "-" + parts[2] + " " + parts[3] + ":" + parts[4];
//        log.info("timeFormatter是"+newFormattedTime);
        return newFormattedTime;
    }

//Java自带的 DateTimeFormatter：
//    private static String convertLocalDateTimeToString(Date time) {
//        LocalDateTime localDateTime = time.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
//        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
//        return localDateTime.format(formatter);
//    }

    // 将 Date 转换为 LocalDateTime 的方法
    private LocalDateTime convertDateToLocalDateTime(Date date) {
        return date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
    }

    //小曲线报警数统计
    @GetMapping("/statistics/alarms")
    @CrossOrigin
    public Result getAlarmStatistics(@RequestParam String workingPositionId,
                                     @RequestParam(name = "dateRange", required = false) String dateRange) {
        log.info("小曲线的线程id:{}", Thread.currentThread().getId()+"名"+Thread.currentThread().getName());

        //System.out.println("dateRange是:" + dateRange);
        List<AlarmStatistics> alarmStatisticsList = new ArrayList<>();
        LocalDate currentDate = null;
        if (dateRange == null) {
            currentDate = LocalDate.now();
//            //System.out.println("currentDate1是"+currentDate);
        } else {
//            //System.out.println("有传时间");
            currentDate = LocalDate.parse(dateRange);
//            // 定义输入日期的格式
//            SimpleDateFormat inputFormat = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'Z (zzzz)");
//            // 定义输出日期的格式
//            SimpleDateFormat outputFormat = new SimpleDateFormat("yyyy-M-d");
//            // 解析第一个日期字符串
//            Date date = inputFormat.parse(dateRange[0]);
//            // 格式化日期
//            String formattedDate = outputFormat.format(date);
//            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//            // 使用format方法格式化日期
//            LocalDate formattedDate = LocalDate.parse(sdf.format(dateRange));
            //System.out.println("currentDate2是"+currentDate);
        }


        // 从 00:00 开始到 24:00（30分钟间隔的总数）
        for (int i = 0; i < 48; i++) { // 30分钟间隔的总数 (24 * 60 / 30)
            AlarmStatistics alarmStatistics = new AlarmStatistics();

            // 计算开始和结束时间
            LocalDateTime startDateTime = currentDate.atStartOfDay().plusMinutes(i * 30);
            LocalDateTime endDateTime = startDateTime.plusMinutes(30);//frequencyProperties.getStatisticsFrequency()

            // 转换为 Date
            Date startTime = Date.from(startDateTime.atZone(ZoneId.systemDefault()).toInstant());
            Date endTime = Date.from(endDateTime.atZone(ZoneId.systemDefault()).toInstant());

//            log.info("开始时间是：" + startTime);
//            log.info("结束时间是：" + endTime);

            // 查询告警数量
            LambdaQueryWrapper<CarStatus> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(workingPositionId != null &&
                            !workingPositionId.isEmpty(),
                    CarStatus::getWorkingPositionId, workingPositionId);
            //排除掉正常的
            queryWrapper.ne(CarStatus::getAlarmLevel, CarStatus.AlarmLevel.normal);
            queryWrapper.between(CarStatus::getCreateTime, startTime, endTime);
//            //从缓存里获取load请求里给的工位信息
//            Object workingPositionId = CacheUtil.getFromCache("workingPositionId");
//            if(workingPositionId!=null){
//                queryWrapper.eq(CarStatus::getWorkingPositionId, workingPositionId);
//            }

            Integer count = carStatusMapper.selectCount(queryWrapper);

//            log.info("count是:" + count);
            // 格式化时间
//            SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
//            String formattedTime = timeFormat.format(endTime);
            // 将 Date 转换为 LocalDateTime
            LocalDateTime localDateTime = endTime.toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDateTime();

            // 获取 LocalTime 部分
            LocalTime localTime = localDateTime.toLocalTime();

            // 输出 LocalTime
//            log.info("Local Time: " + localTime); // 输出 "01:30:00"

            // 如果你想以字符串格式输出
            String formattedTime = String.format("%02d:%02d:%02d",
                    localTime.getHour(), localTime.getMinute(), localTime.getSecond());

//            log.info("formattedTime是"+formattedTime);
            DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");

            // 解析时间字符串
            LocalTime time = LocalTime.parse(formattedTime, timeFormatter);
            alarmStatistics.setDateTime(time);
//            alarmStatistics.setDate(endTime);
            alarmStatistics.setCount(count);
            alarmStatisticsList.add(alarmStatistics);
        }

        return new Result(Code.SELECT_OK, alarmStatisticsList);
    }
//    @GetMapping("/statistics/alarms")
//    public Result getAlarmStatistics() {
//        List<AlarmStatistics> alarmStatisticsList = new ArrayList<>();
////        Calendar calendar = Calendar.getInstance();
//        LocalDate currentDate = LocalDate.now(); // 获取当前日期
//        // 从 00:00 开始到 24:00
//        for (int i = 0; i < 288; i++) { // 5分钟间隔的总数 (24 * 60 / 5)
//            AlarmStatistics alarmStatistics = new AlarmStatistics();
////            calendar.set(Calendar.HOUR_OF_DAY, 0);
////            calendar.set(Calendar.MINUTE, i * 5);
////            calendar.set(Calendar.SECOND, 0);
////            calendar.set(Calendar.MILLISECOND, 0);
////            Date startTime = calendar.getTime();
////
////            calendar.add(Calendar.MINUTE, 5); // 向后加5分钟
////            Date endTime = calendar.getTime();
//
//            LocalDateTime startDateTime = currentDate.atStartOfDay().plusMinutes(i * 5);
//            LocalDateTime endDateTime = startDateTime.plusMinutes(5);
//            // 转换为 Date
//            Date startTime = Date.from(startDateTime.atZone(ZoneId.systemDefault()).toInstant());
//            Date endTime = Date.from(endDateTime.atZone(ZoneId.systemDefault()).toInstant());
//            log.info("开始时间是："+startTime);
//            log.info("结束时间是："+endTime);
//            LambdaQueryWrapper<CarStatus> queryWrapper = new LambdaQueryWrapper<>();
//            queryWrapper.between(CarStatus::getCreateTime, startTime, endTime);
//            // 查询告警数量
//            Integer count = carStatusMapper.selectCount(queryWrapper);//startTime, endTime
//            log.info("count是:"+count);
////            if(count != 0){
////                log.info("count0是:"+count);
////            }
//            alarmStatistics.setDate(endTime);
//            alarmStatistics.setCount(count);
//            alarmStatisticsList.add(alarmStatistics);
//        }
//
//        return new Result(Code.SELECT_OK, alarmStatisticsList);
//    }

}
